1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-11-19 20:31:46 +02:00

Chore: Update plugin types

This commit is contained in:
Laurent Cozic 2024-11-17 16:38:07 +00:00
parent 0868db8c5d
commit d9be5bb6fd
536 changed files with 22516 additions and 1912 deletions

View File

@ -68,6 +68,8 @@ export default class Joplin {
* - [fs-extra](https://www.npmjs.com/package/fs-extra)
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/nativeModule)
*
* <span class="platform-desktop">desktop</span>
*/
require(_path: string): any;
versionInfo(): Promise<import("./types").VersionInfo>;

View File

@ -4,14 +4,20 @@ export default class JoplinClipboard {
constructor(electronClipboard: any, electronNativeImage: any);
readText(): Promise<string>;
writeText(text: string): Promise<void>;
/** <span class="platform-desktop">desktop</span> */
readHtml(): Promise<string>;
/** <span class="platform-desktop">desktop</span> */
writeHtml(html: string): Promise<void>;
/**
* Returns the image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
*
* <span class="platform-desktop">desktop</span>
*/
readImage(): Promise<string>;
/**
* Takes an image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
*
* <span class="platform-desktop">desktop</span>
*/
writeImage(dataUrl: string): Promise<void>;
/**

View File

@ -1,4 +1,5 @@
import { Command } from './types';
import Plugin from '../Plugin';
/**
* This class allows executing or registering new Joplin commands. Commands
* can be executed or associated with
@ -20,6 +21,12 @@ import { Command } from './types';
* To view what arguments are supported, you can open any of these files
* and look at the `execute()` command.
*
* Note that many of these commands only work on desktop. The more limited list of mobile
* commands can be found in these places:
*
* * [Global commands](https://github.com/laurent22/joplin/tree/dev/packages/app-mobile/commands)
* * [Editor commands](https://github.com/laurent22/joplin/blob/dev/packages/app-mobile/components/NoteEditor/commandDeclarations.ts)
*
* ## Executing editor commands
*
* There might be a situation where you want to invoke editor commands
@ -49,9 +56,10 @@ import { Command } from './types';
*
*/
export default class JoplinCommands {
private plugin_;
constructor(plugin_: Plugin);
/**
* <span class="platform-desktop">desktop</span> Executes the given
* command.
* Executes the given command.
*
* The command can take any number of arguments, and the supported
* arguments will vary based on the command. For custom commands, this
@ -70,7 +78,7 @@ export default class JoplinCommands {
*/
execute(commandName: string, ...args: any[]): Promise<any | void>;
/**
* <span class="platform-desktop">desktop</span> Registers a new command.
* Registers a new command.
*
* ```typescript
* // Register a new commmand called "testCommand1"

View File

@ -21,7 +21,8 @@ export default class JoplinContentScripts {
* for more information.
*
* * [View the renderer demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* * [View the editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* * [View the editor plugin tutorial](https://joplinapp.org/help/api/tutorials/cm6_plugin)
* * [View the legacy editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
*
* See also the [postMessage demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*

View File

@ -2,7 +2,7 @@ import { ModelType } from '../../../BaseModel';
import Plugin from '../Plugin';
import { Path } from './types';
/**
* This module provides access to the Joplin data API: https://joplinapp.org/api/references/rest_api/
* This module provides access to the Joplin data API: https://joplinapp.org/help/api/references/rest_api
* This is the main way to retrieve data, such as notes, notebooks, tags, etc.
* or to update them or delete them.
*
@ -13,12 +13,12 @@ import { Path } from './types';
* In general you would use the methods in this class as if you were using a REST API. There are four methods that map to GET, POST, PUT and DELETE calls.
* And each method takes these parameters:
*
* * `path`: This is an array that represents the path to the resource in the form `["resouceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
* * `path`: This is an array that represents the path to the resource in the form `["resourceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
* * `query`: (Optional) The query parameters. In a URL, this is the part after the question mark "?". In this case, it should be an object with key/value pairs.
* * `data`: (Optional) Applies to PUT and POST calls only. The request body contains the data you want to create or modify, for example the content of a note or folder.
* * `files`: (Optional) Used to create new resources and associate them with files.
*
* Please refer to the [Joplin API documentation](https://joplinapp.org/api/references/rest_api/) for complete details about each call. As the plugin runs within the Joplin application **you do not need an authorisation token** to use this API.
* Please refer to the [Joplin API documentation](https://joplinapp.org/help/api/references/rest_api) for complete details about each call. As the plugin runs within the Joplin application **you do not need an authorisation token** to use this API.
*
* For example:
*

View File

@ -1,3 +1,4 @@
import { FilterHandler } from '../../../eventManager';
/**
* @ignore
*
@ -5,6 +6,6 @@
* so for now disable filters.
*/
export default class JoplinFilters {
on(name: string, callback: Function): Promise<void>;
off(name: string, callback: Function): Promise<void>;
on(name: string, callback: FilterHandler): Promise<void>;
off(name: string, callback: FilterHandler): Promise<void>;
}

View File

@ -1,12 +1,33 @@
import { Rectangle } from './types';
export interface Implementation {
nativeImage: any;
}
export interface CreateFromBufferOptions {
width?: number;
height?: number;
scaleFactor?: number;
}
export interface CreateFromPdfOptions {
/**
* The first page to export. Defaults to `1`, the first page in
* the document.
*/
minPage?: number;
/**
* The number of the last page to convert. Defaults to the last page
* if not given.
*
* If `maxPage` is greater than the number of pages in the PDF, all pages
* in the PDF will be converted to images.
*/
maxPage?: number;
scaleFactor?: number;
}
export interface PdfInfo {
pageCount: number;
}
export interface Implementation {
createFromPath: (path: string) => Promise<unknown>;
createFromPdf: (path: string, options: CreateFromPdfOptions) => Promise<unknown[]>;
getPdfInfo: (path: string) => Promise<PdfInfo>;
}
export interface ResizeOptions {
width?: number;
height?: number;
@ -24,6 +45,7 @@ export type Handle = string;
* [View the
* example](https://github.com/laurent22/joplin/blob/dev/packages/app-cli/tests/support/plugins/imaging/src/index.ts)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinImaging {
private implementation_;
@ -32,11 +54,20 @@ export default class JoplinImaging {
private createImageHandle;
private imageByHandle;
private cacheImage;
/**
* Creates an image from the provided path. Note that images and PDFs are supported. If you
* provide a URL instead of a local path, the file will be downloaded first then converted to an
* image.
*/
createFromPath(filePath: string): Promise<Handle>;
createFromResource(resourceId: string): Promise<Handle>;
createFromPdfPath(path: string, options?: CreateFromPdfOptions): Promise<Handle[]>;
createFromPdfResource(resourceId: string, options?: CreateFromPdfOptions): Promise<Handle[]>;
getPdfInfoFromPath(path: string): Promise<PdfInfo>;
getPdfInfoFromResource(resourceId: string): Promise<PdfInfo>;
getSize(handle: Handle): Promise<any>;
resize(handle: Handle, options?: ResizeOptions): Promise<string>;
crop(handle: Handle, rectange: Rectangle): Promise<string>;
crop(handle: Handle, rectangle: Rectangle): Promise<string>;
toPngFile(handle: Handle, filePath: string): Promise<void>;
/**
* Quality is between 0 and 100
@ -57,5 +88,5 @@ export default class JoplinImaging {
* Image data is not automatically deleted by Joplin so make sure you call
* this method on the handle once you are done.
*/
free(handle: Handle): Promise<void>;
free(handles: Handle[] | Handle): Promise<void>;
}

View File

@ -9,7 +9,10 @@ import { ExportModule, ImportModule } from './types';
*
* See the documentation of the [[ExportModule]] and [[ImportModule]] for more information.
*
* You may also want to refer to the Joplin API documentation to see the list of properties for each item (note, notebook, etc.) - https://joplinapp.org/api/references/rest_api/
* You may also want to refer to the Joplin API documentation to see the list of properties for each item (note, notebook, etc.) - https://joplinapp.org/help/api/references/rest_api
*
* <span class="platform-desktop">desktop</span>: While it is possible to register import and export
* modules on mobile, there is no GUI to activate them.
*/
export default class JoplinInterop {
registerExportModule(module: ExportModule): Promise<void>;

View File

@ -19,8 +19,6 @@ export type ChangeHandler = (event: ChangeEvent) => void;
export default class JoplinSettings {
private plugin_;
constructor(plugin: Plugin);
private get keyPrefix();
private namespacedKey;
/**
* Registers new settings.
* Note that registering a setting item is dynamic and will be gone next time Joplin starts.
@ -40,6 +38,12 @@ export default class JoplinSettings {
*/
registerSection(name: string, section: SettingSection): Promise<void>;
/**
* Gets setting values (only applies to setting you registered from your plugin)
*/
values(keys: string[] | string): Promise<Record<string, unknown>>;
/**
* @deprecated Use joplin.settings.values()
*
* Gets a setting value (only applies to setting you registered from your plugin)
*/
value(key: string): Promise<any>;

View File

@ -5,6 +5,7 @@ import JoplinViewsMenus from './JoplinViewsMenus';
import JoplinViewsToolbarButtons from './JoplinViewsToolbarButtons';
import JoplinViewsPanels from './JoplinViewsPanels';
import JoplinViewsNoteList from './JoplinViewsNoteList';
import JoplinViewsEditors from './JoplinViewsEditor';
/**
* This namespace provides access to view-related services.
*
@ -19,11 +20,13 @@ export default class JoplinViews {
private menus_;
private toolbarButtons_;
private dialogs_;
private editors_;
private noteList_;
private implementation_;
constructor(implementation: any, plugin: Plugin, store: any);
get dialogs(): JoplinViewsDialogs;
get panels(): JoplinViewsPanels;
get editors(): JoplinViewsEditors;
get menuItems(): JoplinViewsMenuItems;
get menus(): JoplinViewsMenus;
get toolbarButtons(): JoplinViewsToolbarButtons;

View File

@ -43,6 +43,14 @@ export default class JoplinViewsDialogs {
* Displays a message box with OK/Cancel buttons. Returns the button index that was clicked - "0" for OK and "1" for "Cancel"
*/
showMessageBox(message: string): Promise<number>;
/**
* Displays a dialog to select a file or a directory. Same options and
* output as
* https://www.electronjs.org/docs/latest/api/dialog#dialogshowopendialogbrowserwindow-options
*
* <span class="platform-desktop">desktop</span>
*/
showOpenDialog(options: any): Promise<any>;
/**
* Sets the dialog HTML content
*/
@ -56,7 +64,9 @@ export default class JoplinViewsDialogs {
*/
setButtons(handle: ViewHandle, buttons: ButtonSpec[]): Promise<ButtonSpec[]>;
/**
* Opens the dialog
* Opens the dialog.
*
* On desktop, this closes any copies of the dialog open in different windows.
*/
open(handle: ViewHandle): Promise<DialogResult>;
/**

View File

@ -0,0 +1,88 @@
import Plugin from '../Plugin';
import { ActivationCheckCallback, ViewHandle, UpdateCallback } from './types';
/**
* Allows creating alternative note editors. You can create a view to handle loading and saving the
* note, and do your own rendering.
*
* Although it may be used to implement an alternative text editor, the more common use case may be
* to render the note in a different, graphical way - for example displaying a graph, and
* saving/loading the graph data in the associated note. In that case, you would detect whether the
* current note contains graph data and, in this case, you'd display your viewer.
*
* Terminology: An editor is **active** when it can be used to edit the current note. Note that it
* doesn't necessarily mean that your editor is visible - it just means that the user has the option
* to switch to it (via the "toggle editor" button). A **visible** editor is active and is currently
* being displayed.
*
* To implement an editor you need to listen to two events:
*
* - `onActivationCheck`: This is a way for the app to know whether your editor should be active or
* not. Return `true` from this handler to activate your editor.
*
* - `onUpdate`: When this is called you should update your editor based on the current note
* content. Call `joplin.workspace.selectedNote()` to get the current note.
*
* - `showEditorPlugin` and `toggleEditorPlugin` commands. Additionally you can use these commands
* to display your editor via `joplin.commands.execute('showEditorPlugin')`. This is not always
* necessary since the user can switch to your editor using the "toggle editor" button, however
* you may want to programmatically display the editor in some cases - for example when creating a
* new note specific to your editor.
*
* Note that only one editor view can be active at a time. This is why it is important not to
* activate your view if it's not relevant to the current note. If more than one is active, it is
* undefined which editor is going to be used to display the note.
*
* For an example of editor plugin, see the [YesYouKan
* plugin](https://github.com/joplin/plugin-yesyoukan/blob/master/src/index.ts). In particular,
* check the logic around `onActivationCheck` and `onUpdate` since this is the entry points for
* using this API.
*/
export default class JoplinViewsEditors {
private store;
private plugin;
private activationCheckHandlers_;
constructor(plugin: Plugin, store: any);
private controller;
/**
* Creates a new editor view
*/
create(id: string): Promise<ViewHandle>;
/**
* Sets the editor HTML content
*/
setHtml(handle: ViewHandle, html: string): Promise<string>;
/**
* Adds and loads a new JS or CSS file into the panel.
*/
addScript(handle: ViewHandle, scriptPath: string): Promise<void>;
/**
* See [[JoplinViewPanels]]
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Emitted when the editor can potentially be activated - this for example when the current note
* is changed, or when the application is opened. At that point should can check the current
* note and decide whether your editor should be activated or not. If it should return `true`,
* otherwise return `false`.
*/
onActivationCheck(handle: ViewHandle, callback: ActivationCheckCallback): Promise<void>;
/**
* Emitted when the editor content should be updated. This for example when the currently
* selected note changes, or when the user makes the editor visible.
*/
onUpdate(handle: ViewHandle, callback: UpdateCallback): Promise<void>;
/**
* See [[JoplinViewPanels]]
*/
postMessage(handle: ViewHandle, message: any): void;
/**
* Tells whether the editor is active or not.
*/
isActive(handle: ViewHandle): Promise<boolean>;
/**
* Tells whether the editor is effectively visible or not. If the editor is inactive, this will
* return `false`. If the editor is active and the user has switched to it, it will return
* `true`. Otherwise it will return `false`.
*/
isVisible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -4,6 +4,8 @@ import Plugin from '../Plugin';
* Allows creating and managing menu items.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/register_command)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsMenuItems {
private store;

View File

@ -4,6 +4,8 @@ import Plugin from '../Plugin';
* Allows creating menus.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/menu)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsMenus {
private store;

View File

@ -1,6 +1,39 @@
import { Store } from 'redux';
import Plugin from '../Plugin';
import { ListRenderer } from './noteListType';
/**
* This API allows you to customise how each note in the note list is rendered.
* The renderer you implement follows a unidirectional data flow.
*
* The app provides the required dependencies whenever a note is updated - you
* process these dependencies, and return some props, which are then passed to
* your template and rendered. See [[ListRenderer]] for a detailed description
* of each property of the renderer.
*
* ## Reference
*
* * [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/note_list_renderer)
*
* * [Default simple renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultListRenderer.ts)
*
* * [Default detailed renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultMultiColumnsRenderer.ts)
*
* ## Screenshots:
*
* ### Top to bottom with title, date and body
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/TopToBottom.png"/>
*
* ### Left to right with thumbnails
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/LeftToRight_Thumbnails.png"/>
*
* ### Top to bottom with editable title
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/TopToBottom_Editable.png"/>
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsNoteList {
private plugin_;
private store_;

View File

@ -1,12 +1,17 @@
import Plugin from '../Plugin';
import { ViewHandle } from './types';
/**
* Allows creating and managing view panels. View panels currently are
* displayed at the right of the sidebar and allows displaying any HTML
* content (within a webview) and update it in real-time. For example it
* Allows creating and managing view panels. View panels allow displaying any HTML
* content (within a webview) and updating it in real-time. For example it
* could be used to display a table of content for the active note, or
* display various metadata or graph.
*
* On desktop, view panels currently are displayed at the right of the sidebar, though can
* be moved with "View" > "Change application layout".
*
* On mobile, view panels are shown in a tabbed dialog that can be opened using a
* toolbar button.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/toc)
*/
export default class JoplinViewsPanels {
@ -75,4 +80,5 @@ export default class JoplinViewsPanels {
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
isActive(handle: ViewHandle): Promise<boolean>;
}

View File

@ -1,17 +1,14 @@
import Plugin from '../Plugin';
export interface Implementation {
injectCustomStyles(elementId: string, cssFilePath: string): Promise<void>;
}
export default class JoplinWindow {
private plugin_;
private store_;
private implementation_;
constructor(implementation: Implementation, plugin: Plugin, store: any);
constructor(_plugin: Plugin, store: any);
/**
* Loads a chrome CSS file. It will apply to the window UI elements, except
* for the note viewer. It is the same as the "Custom stylesheet for
* Joplin-wide app styles" setting. See the [Load CSS Demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/load_css)
* for an example.
*
* <span class="platform-desktop">desktop</span>
*/
loadChromeCssFile(filePath: string): Promise<void>;
/**
@ -19,6 +16,8 @@ export default class JoplinWindow {
* exported or printed note. It is the same as the "Custom stylesheet for
* rendered Markdown" setting. See the [Load CSS Demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/load_css)
* for an example.
*
* <span class="platform-desktop">desktop</span>
*/
loadNoteCssFile(filePath: string): Promise<void>;
}

View File

@ -1,9 +1,6 @@
import Plugin from '../Plugin';
import { FolderEntity } from '../../database/types';
import { Disposable, MenuItem } from './types';
export interface EditContextMenuFilterObject {
items: MenuItem[];
}
type FilterHandler<T> = (object: T) => Promise<void>;
import { Disposable, EditContextMenuFilterObject, FilterHandler } from './types';
declare enum ItemChangeEventType {
Create = 1,
Update = 2,
@ -13,15 +10,25 @@ interface ItemChangeEvent {
id: string;
event: ItemChangeEventType;
}
interface SyncStartEvent {
withErrors: boolean;
}
interface ResourceChangeEvent {
id: string;
}
type ItemChangeHandler = (event: ItemChangeEvent) => void;
type SyncStartHandler = (event: SyncStartEvent) => void;
type ResourceChangeHandler = (event: ResourceChangeEvent) => void;
interface NoteContentChangeEvent {
note: any;
}
interface NoteSelectionChangeEvent {
value: string[];
}
interface NoteAlarmTriggerEvent {
noteId: string;
}
interface SyncCompleteEvent {
withErrors: boolean;
}
type WorkspaceEventHandler<EventType> = (event: EventType) => void;
type ItemChangeHandler = WorkspaceEventHandler<ItemChangeEvent>;
type SyncStartHandler = () => void;
type ResourceChangeHandler = WorkspaceEventHandler<ResourceChangeEvent>;
/**
* The workspace service provides access to all the parts of Joplin that
* are being worked on - i.e. the currently selected notes or notebooks as
@ -32,16 +39,17 @@ type ResourceChangeHandler = (event: ResourceChangeEvent) => void;
*/
export default class JoplinWorkspace {
private store;
constructor(store: any);
private plugin;
constructor(plugin: Plugin, store: any);
/**
* Called when a new note or notes are selected.
*/
onNoteSelectionChange(callback: Function): Promise<Disposable>;
onNoteSelectionChange(callback: WorkspaceEventHandler<NoteSelectionChangeEvent>): Promise<Disposable>;
/**
* Called when the content of a note changes.
* @deprecated Use `onNoteChange()` instead, which is reliably triggered whenever the note content, or any note property changes.
*/
onNoteContentChange(callback: Function): Promise<void>;
onNoteContentChange(callback: WorkspaceEventHandler<NoteContentChangeEvent>): Promise<void>;
/**
* Called when the content of the current note changes.
*/
@ -54,7 +62,7 @@ export default class JoplinWorkspace {
/**
* Called when an alarm associated with a to-do is triggered.
*/
onNoteAlarmTrigger(handler: Function): Promise<Disposable>;
onNoteAlarmTrigger(handler: WorkspaceEventHandler<NoteAlarmTriggerEvent>): Promise<Disposable>;
/**
* Called when the synchronisation process is starting.
*/
@ -62,14 +70,16 @@ export default class JoplinWorkspace {
/**
* Called when the synchronisation process has finished.
*/
onSyncComplete(callback: Function): Promise<Disposable>;
onSyncComplete(callback: WorkspaceEventHandler<SyncCompleteEvent>): Promise<Disposable>;
/**
* Called just before the editor context menu is about to open. Allows
* adding items to it.
*
* <span class="platform-desktop">desktop</span>
*/
filterEditorContextMenu(handler: FilterHandler<EditContextMenuFilterObject>): void;
/**
* Gets the currently selected note
* Gets the currently selected note. Will be `null` if no note is selected.
*/
selectedNote(): Promise<any>;
/**

View File

@ -1,5 +1,5 @@
import { Size } from './types';
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.deleted_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_data' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.deleted_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
export declare enum ItemFlow {
TopToBottom = "topToBottom",
LeftToRight = "leftToRight"
@ -10,18 +10,245 @@ export interface OnChangeEvent {
value: any;
noteId: string;
}
export interface OnClickEvent {
elementId: string;
}
export type OnRenderNoteHandler = (props: any) => Promise<RenderNoteView>;
export type OnChangeHandler = (event: OnChangeEvent) => Promise<void>;
export type ListRendererDepependency = ListRendererDatabaseDependency | 'item.size.width' | 'item.size.height' | 'item.selected' | 'note.titleHtml' | 'note.isWatched' | 'note.tags';
export type OnClickHandler = (event: OnClickEvent) => Promise<void>;
/**
* Most of these are the built-in note properties, such as `note.title`, `note.todo_completed`, etc.
* complemented with special properties such as `note.isWatched`, to know if a note is currently
* opened in the external editor, and `note.tags` to get the list tags associated with the note.
*
* The `note.todoStatusText` property is a localised description of the to-do status (e.g.
* "to-do, incomplete"). If you include an `<input type='checkbox' ... />` for to-do items that would
* otherwise be unlabelled, consider adding `note.todoStatusText` as the checkbox's `aria-label`.
*
* ## Item properties
*
* The `item.*` properties are specific to the rendered item. The most important being
* `item.selected`, which you can use to display the selected note in a different way.
*/
export type ListRendererDependency = ListRendererDatabaseDependency | 'item.index' | 'item.selected' | 'item.size.height' | 'item.size.width' | 'note.folder.title' | 'note.isWatched' | 'note.tags' | 'note.todoStatusText' | 'note.titleHtml';
export type ListRendererItemValueTemplates = Record<string, string>;
export declare const columnNames: readonly ["note.folder.title", "note.is_todo", "note.latitude", "note.longitude", "note.source_url", "note.tags", "note.title", "note.todo_completed", "note.todo_due", "note.user_created_time", "note.user_updated_time"];
export type ColumnName = typeof columnNames[number];
export interface ListRenderer {
/**
* It must be unique to your plugin.
*/
id: string;
/**
* Can be top to bottom or left to right. Left to right gives you more
* option to set the size of the items since you set both its width and
* height.
*/
flow: ItemFlow;
/**
* Whether the renderer supports multiple columns. Applies only when `flow`
* is `topToBottom`. Defaults to `false`.
*/
multiColumns?: boolean;
/**
* The size of each item must be specified in advance for performance
* reasons, and cannot be changed afterwards. If the item flow is top to
* bottom, you only need to specify the item height (the width will be
* ignored).
*/
itemSize: Size;
/**
* The CSS is relative to the list item container. What will appear in the
* page is essentially `.note-list-item { YOUR_CSS; }`. It means you can use
* child combinator with guarantee it will only apply to your own items. In
* this example, the styling will apply to `.note-list-item > .content`:
*
* ```css
* > .content {
* padding: 10px;
* }
* ```
*
* In order to get syntax highlighting working here, it's recommended
* installing an editor extension such as [es6-string-html VSCode
* extension](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
*/
itemCss?: string;
dependencies: ListRendererDepependency[];
/**
* List the dependencies that your plugin needs to render the note list
* items. Only these will be passed to your `onRenderNote` handler. Ensure
* that you do not add more than what you need since there is a performance
* penalty for each property.
*/
dependencies?: ListRendererDependency[];
headerTemplate?: string;
headerHeight?: number;
onHeaderClick?: OnClickHandler;
/**
* This property is set differently depending on the `multiColumns` property.
*
* ## If `multiColumns` is `false`
*
* There is only one column and the template is used to render the entire row.
*
* This is the HTML template that will be used to render the note list item. This is a [Mustache
* template](https://github.com/janl/mustache.js) and it will receive the variable you return
* from `onRenderNote` as tags. For example, if you return a property named `formattedDate` from
* `onRenderNote`, you can insert it in the template using `Created date: {{formattedDate}}`
*
* ## If `multiColumns` is `true`
*
* Since there is multiple columns, this template will be used to render each note property
* within the row. For example if the current columns are the Updated and Title properties, this
* template will be called once to render the updated time and a second time to render the
* title. To display the current property, the generic `value` property is provided - it will be
* replaced at runtime by the actual note property. To render something different depending on
* the note property, use `itemValueTemplate`. A minimal example would be
* `<span>{{value}}</span>` which will simply render the current property inside a span tag.
*
* In order to get syntax highlighting working here, it's recommended installing an editor
* extension such as [es6-string-html VSCode
* extension](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
*
* ## Default property rendering
*
* Certain properties are automatically rendered once inserted in the Mustache template. Those
* are in particular all the date-related fields, such as `note.user_updated_time` or
* `note.todo_completed`. Internally, those are timestamps in milliseconds, however when
* rendered we display them as date/time strings using the user's preferred time format. Another
* notable auto-rendered property is `note.title` which is going to include additional HTML,
* such as the search markers.
*
* If you do not want this default rendering behaviour, for example if you want to display the
* raw timestamps in milliseconds, you can simply return custom properties from
* `onRenderNote()`. For example:
*
* ```typescript
* onRenderNote: async (props: any) => {
* return {
* ...props,
* // Return the property under a different name
* updatedTimeMs: props.note.user_updated_time,
* }
* },
*
* itemTemplate: // html
* `
* <div>
* Raw timestamp: {{updatedTimeMs}} <!-- This is **not** auto-rendered ->
* Formatted time: {{note.user_updated_time}} <!-- This is -->
* </div>
* `,
*
* ```
*
* See
* `[https://github.com/laurent22/joplin/blob/dev/packages/lib/services/noteList/renderViewProps.ts](renderViewProps.ts)`
* for the list of properties that have a default rendering.
*/
itemTemplate: string;
/**
* This property applies only when `multiColumns` is `true`. It is used to render something
* different for each note property.
*
* This is a map of actual dependencies to templates - you only need to return something if the
* default, as specified in `template`, is not enough.
*
* Again you need to return a Mustache template and it will be combined with the `template`
* property to create the final template. For example if you return a property named
* `formattedDate` from `onRenderNote`, you can insert it in the template using
* `{{formattedDate}}`. This string will replace `{{value}}` in the `template` property.
*
* So if the template property is set to `<span>{{value}}</span>`, the final template will be
* `<span>{{formattedDate}}</span>`.
*
* The property would be set as so:
*
* ```javascript
* itemValueTemplates: {
* 'note.user_updated_time': '{{formattedDate}}',
* }
* ```
*/
itemValueTemplates?: ListRendererItemValueTemplates;
/**
* This user-facing text is used for example in the View menu, so that your
* renderer can be selected.
*/
label: () => Promise<string>;
/**
* This is where most of the real-time processing will happen. When a note
* is rendered for the first time and every time it changes, this handler
* receives the properties specified in the `dependencies` property. You can
* then process them, load any additional data you need, and once done you
* need to return the properties that are needed in the `itemTemplate` HTML.
* Again, to use the formatted date example, you could have such a renderer:
*
* ```typescript
* dependencies: [
* 'note.title',
* 'note.created_time',
* ],
*
* itemTemplate: // html
* `
* <div>
* Title: {{note.title}}<br/>
* Date: {{formattedDate}}
* </div>
* `,
*
* onRenderNote: async (props: any) => {
* const formattedDate = dayjs(props.note.created_time).format();
* return {
* // Also return the props, so that note.title is available from the
* // template
* ...props,
* formattedDate,
* }
* },
* ```
*/
onRenderNote: OnRenderNoteHandler;
/**
* This handler allows adding some interactivity to the note renderer - whenever an input element
* within the item is changed (for example, when a checkbox is clicked, or a text input is
* changed), this `onChange` handler is going to be called.
*
* You can inspect `event.elementId` to know which element had some changes, and `event.value`
* to know the new value. `event.noteId` also tells you what note is affected, so that you can
* potentially apply changes to it.
*
* You specify the element ID, by setting a `data-id` attribute on the input.
*
* For example, if you have such a template:
*
* ```html
* <div>
* <input type="text" value="{{note.title}}" data-id="noteTitleInput"/>
* </div>
* ```
*
* The event handler will receive an event with `elementId` set to `noteTitleInput`.
*
* ## Default event handlers
*
* Currently one click event is automatically handled:
*
* If there is a checkbox with a `data-id="todo-checkbox"` attribute is present, it is going to
* automatically toggle the note to-do "completed" status.
*
* For example this is what is used in the default list renderer:
*
* `<input data-id="todo-checkbox" type="checkbox" {{#note.todo_completed}}checked="checked"{{/note.todo_completed}}>`
*/
onChange?: OnChangeHandler;
}
export interface NoteListColumn {
name: ColumnName;
width: number;
}
export type NoteListColumns = NoteListColumn[];
export declare const defaultWidth = 100;
export declare const defaultListColumns: () => NoteListColumns;
export {};

View File

@ -1,7 +1,9 @@
/* eslint-disable multiline-comment-style */
import { Size } from './types';
// AUTO-GENERATED by generate-database-type
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.deleted_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_data' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.deleted_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
// AUTO-GENERATED by generate-database-type
export enum ItemFlow {
@ -9,34 +11,315 @@ export enum ItemFlow {
LeftToRight = 'leftToRight',
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export type RenderNoteView = Record<string, any>;
export interface OnChangeEvent {
elementId: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value: any;
noteId: string;
}
export interface OnClickEvent {
elementId: string;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export type OnRenderNoteHandler = (props: any)=> Promise<RenderNoteView>;
export type OnChangeHandler = (event: OnChangeEvent)=> Promise<void>;
export type OnClickHandler = (event: OnClickEvent)=> Promise<void>;
export type ListRendererDepependency =
/**
* Most of these are the built-in note properties, such as `note.title`, `note.todo_completed`, etc.
* complemented with special properties such as `note.isWatched`, to know if a note is currently
* opened in the external editor, and `note.tags` to get the list tags associated with the note.
*
* The `note.todoStatusText` property is a localised description of the to-do status (e.g.
* "to-do, incomplete"). If you include an `<input type='checkbox' ... />` for to-do items that would
* otherwise be unlabelled, consider adding `note.todoStatusText` as the checkbox's `aria-label`.
*
* ## Item properties
*
* The `item.*` properties are specific to the rendered item. The most important being
* `item.selected`, which you can use to display the selected note in a different way.
*/
export type ListRendererDependency =
ListRendererDatabaseDependency |
'item.size.width' |
'item.size.height' |
'item.index' |
'item.selected' |
'note.titleHtml' |
'item.size.height' |
'item.size.width' |
'note.folder.title' |
'note.isWatched' |
'note.tags';
'note.tags' |
'note.todoStatusText' |
'note.titleHtml';
export type ListRendererItemValueTemplates = Record<string, string>;
export const columnNames = [
'note.folder.title',
'note.is_todo',
'note.latitude',
'note.longitude',
'note.source_url',
'note.tags',
'note.title',
'note.todo_completed',
'note.todo_due',
'note.user_created_time',
'note.user_updated_time',
] as const;
export type ColumnName = typeof columnNames[number];
export interface ListRenderer {
/**
* It must be unique to your plugin.
*/
id: string;
/**
* Can be top to bottom or left to right. Left to right gives you more
* option to set the size of the items since you set both its width and
* height.
*/
flow: ItemFlow;
/**
* Whether the renderer supports multiple columns. Applies only when `flow`
* is `topToBottom`. Defaults to `false`.
*/
multiColumns?: boolean;
/**
* The size of each item must be specified in advance for performance
* reasons, and cannot be changed afterwards. If the item flow is top to
* bottom, you only need to specify the item height (the width will be
* ignored).
*/
itemSize: Size;
/**
* The CSS is relative to the list item container. What will appear in the
* page is essentially `.note-list-item { YOUR_CSS; }`. It means you can use
* child combinator with guarantee it will only apply to your own items. In
* this example, the styling will apply to `.note-list-item > .content`:
*
* ```css
* > .content {
* padding: 10px;
* }
* ```
*
* In order to get syntax highlighting working here, it's recommended
* installing an editor extension such as [es6-string-html VSCode
* extension](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
*/
itemCss?: string;
dependencies: ListRendererDepependency[];
/**
* List the dependencies that your plugin needs to render the note list
* items. Only these will be passed to your `onRenderNote` handler. Ensure
* that you do not add more than what you need since there is a performance
* penalty for each property.
*/
dependencies?: ListRendererDependency[];
headerTemplate?: string;
headerHeight?: number;
onHeaderClick?: OnClickHandler;
/**
* This property is set differently depending on the `multiColumns` property.
*
* ## If `multiColumns` is `false`
*
* There is only one column and the template is used to render the entire row.
*
* This is the HTML template that will be used to render the note list item. This is a [Mustache
* template](https://github.com/janl/mustache.js) and it will receive the variable you return
* from `onRenderNote` as tags. For example, if you return a property named `formattedDate` from
* `onRenderNote`, you can insert it in the template using `Created date: {{formattedDate}}`
*
* ## If `multiColumns` is `true`
*
* Since there is multiple columns, this template will be used to render each note property
* within the row. For example if the current columns are the Updated and Title properties, this
* template will be called once to render the updated time and a second time to render the
* title. To display the current property, the generic `value` property is provided - it will be
* replaced at runtime by the actual note property. To render something different depending on
* the note property, use `itemValueTemplate`. A minimal example would be
* `<span>{{value}}</span>` which will simply render the current property inside a span tag.
*
* In order to get syntax highlighting working here, it's recommended installing an editor
* extension such as [es6-string-html VSCode
* extension](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
*
* ## Default property rendering
*
* Certain properties are automatically rendered once inserted in the Mustache template. Those
* are in particular all the date-related fields, such as `note.user_updated_time` or
* `note.todo_completed`. Internally, those are timestamps in milliseconds, however when
* rendered we display them as date/time strings using the user's preferred time format. Another
* notable auto-rendered property is `note.title` which is going to include additional HTML,
* such as the search markers.
*
* If you do not want this default rendering behaviour, for example if you want to display the
* raw timestamps in milliseconds, you can simply return custom properties from
* `onRenderNote()`. For example:
*
* ```typescript
* onRenderNote: async (props: any) => {
* return {
* ...props,
* // Return the property under a different name
* updatedTimeMs: props.note.user_updated_time,
* }
* },
*
* itemTemplate: // html
* `
* <div>
* Raw timestamp: {{updatedTimeMs}} <!-- This is **not** auto-rendered ->
* Formatted time: {{note.user_updated_time}} <!-- This is -->
* </div>
* `,
*
* ```
*
* See
* `[https://github.com/laurent22/joplin/blob/dev/packages/lib/services/noteList/renderViewProps.ts](renderViewProps.ts)`
* for the list of properties that have a default rendering.
*/
itemTemplate: string;
/**
* This property applies only when `multiColumns` is `true`. It is used to render something
* different for each note property.
*
* This is a map of actual dependencies to templates - you only need to return something if the
* default, as specified in `template`, is not enough.
*
* Again you need to return a Mustache template and it will be combined with the `template`
* property to create the final template. For example if you return a property named
* `formattedDate` from `onRenderNote`, you can insert it in the template using
* `{{formattedDate}}`. This string will replace `{{value}}` in the `template` property.
*
* So if the template property is set to `<span>{{value}}</span>`, the final template will be
* `<span>{{formattedDate}}</span>`.
*
* The property would be set as so:
*
* ```javascript
* itemValueTemplates: {
* 'note.user_updated_time': '{{formattedDate}}',
* }
* ```
*/
itemValueTemplates?: ListRendererItemValueTemplates;
/**
* This user-facing text is used for example in the View menu, so that your
* renderer can be selected.
*/
label: ()=> Promise<string>;
/**
* This is where most of the real-time processing will happen. When a note
* is rendered for the first time and every time it changes, this handler
* receives the properties specified in the `dependencies` property. You can
* then process them, load any additional data you need, and once done you
* need to return the properties that are needed in the `itemTemplate` HTML.
* Again, to use the formatted date example, you could have such a renderer:
*
* ```typescript
* dependencies: [
* 'note.title',
* 'note.created_time',
* ],
*
* itemTemplate: // html
* `
* <div>
* Title: {{note.title}}<br/>
* Date: {{formattedDate}}
* </div>
* `,
*
* onRenderNote: async (props: any) => {
* const formattedDate = dayjs(props.note.created_time).format();
* return {
* // Also return the props, so that note.title is available from the
* // template
* ...props,
* formattedDate,
* }
* },
* ```
*/
onRenderNote: OnRenderNoteHandler;
/**
* This handler allows adding some interactivity to the note renderer - whenever an input element
* within the item is changed (for example, when a checkbox is clicked, or a text input is
* changed), this `onChange` handler is going to be called.
*
* You can inspect `event.elementId` to know which element had some changes, and `event.value`
* to know the new value. `event.noteId` also tells you what note is affected, so that you can
* potentially apply changes to it.
*
* You specify the element ID, by setting a `data-id` attribute on the input.
*
* For example, if you have such a template:
*
* ```html
* <div>
* <input type="text" value="{{note.title}}" data-id="noteTitleInput"/>
* </div>
* ```
*
* The event handler will receive an event with `elementId` set to `noteTitleInput`.
*
* ## Default event handlers
*
* Currently one click event is automatically handled:
*
* If there is a checkbox with a `data-id="todo-checkbox"` attribute is present, it is going to
* automatically toggle the note to-do "completed" status.
*
* For example this is what is used in the default list renderer:
*
* `<input data-id="todo-checkbox" type="checkbox" {{#note.todo_completed}}checked="checked"{{/note.todo_completed}}>`
*/
onChange?: OnChangeHandler;
}
export interface NoteListColumn {
name: ColumnName;
width: number;
}
export type NoteListColumns = NoteListColumn[];
export const defaultWidth = 100;
export const defaultListColumns = () => {
const columns: NoteListColumns = [
{
name: 'note.is_todo',
width: 30,
},
{
name: 'note.user_updated_time',
width: defaultWidth,
},
{
name: 'note.title',
width: 0,
},
];
return columns;
};

View File

@ -26,6 +26,7 @@ export interface Command {
/**
* Code to be ran when the command is executed. It may return a result.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
execute(...args: any[]): Promise<any | void>;
/**
@ -115,11 +116,13 @@ export interface ExportModule {
/**
* Called when an item needs to be processed. An "item" can be any Joplin object, such as a note, a folder, a notebook, etc.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onProcessItem(context: ExportContext, itemType: number, item: any): Promise<void>;
/**
* Called when a resource file needs to be exported.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onProcessResource(context: ExportContext, resource: any, filePath: string): Promise<void>;
/**
@ -181,13 +184,15 @@ export interface ExportContext {
options: ExportOptions;
/**
* You can attach your own custom data using this propery - it will then be passed to each event handler, allowing you to keep state from one event to the next.
* You can attach your own custom data using this property - it will then be passed to each event handler, allowing you to keep state from one event to the next.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
userData?: any;
}
export interface ImportContext {
sourcePath: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
options: any;
warnings: string[];
}
@ -197,6 +202,7 @@ export interface ImportContext {
// =================================================================
export interface Script {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onStart?(event: any): Promise<void>;
}
@ -227,6 +233,8 @@ export interface VersionInfo {
version: string;
profileVersion: number;
syncVersion: number;
platform: 'desktop'|'mobile';
}
// =================================================================
@ -300,6 +308,7 @@ export interface MenuItem {
* Arguments that should be passed to the command. They will be as rest
* parameters.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
commandArgs?: any[];
/**
@ -338,6 +347,8 @@ export type ButtonId = string;
export enum ToolbarButtonLocation {
/**
* This toolbar in the top right corner of the application. It applies to the note as a whole, including its metadata.
*
* <span class="platform-desktop">desktop</span>
*/
NoteToolbar = 'noteToolbar',
@ -351,11 +362,13 @@ export type ViewHandle = string;
export interface EditorCommand {
name: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value?: any;
}
export interface DialogResult {
id: ButtonId;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
formData?: any;
}
@ -371,6 +384,26 @@ export interface Rectangle {
height?: number;
}
export type ActivationCheckCallback = ()=> Promise<boolean>;
export type UpdateCallback = ()=> Promise<void>;
export type VisibleHandler = ()=> Promise<void>;
export interface EditContextMenuFilterObject {
items: MenuItem[];
}
export interface EditorActivationCheckFilterObject {
activatedEditors: {
pluginId: string;
viewId: string;
isActive: boolean;
}[];
}
export type FilterHandler<T> = (object: T)=> Promise<T>;
// =================================================================
// Settings types
// =================================================================
@ -404,6 +437,7 @@ export enum SettingStorage {
// Redefine a simplified interface to mask internal details
// and to remove function calls as they would have to be async.
export interface SettingItem {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value: any;
type: SettingItemType;
@ -440,6 +474,7 @@ export interface SettingItem {
* This property is required when `isEnum` is `true`. In which case, it
* should contain a map of value => label.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
options?: Record<any, any>;
/**
@ -497,6 +532,7 @@ export type Path = string[];
// Content Script types
// =================================================================
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export type PostMessageHandler = (message: any)=> Promise<any>;
/**
@ -519,6 +555,67 @@ export interface ContentScriptContext {
postMessage: PostMessageHandler;
}
export interface ContentScriptModuleLoadedEvent {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
userData?: any;
}
export interface ContentScriptModule {
onLoaded?: (event: ContentScriptModuleLoadedEvent)=> void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
plugin: ()=> any;
assets?: ()=> void;
}
export interface MarkdownItContentScriptModule extends Omit<ContentScriptModule, 'plugin'> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
plugin: (markdownIt: any, options: any)=> any;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
type EditorCommandCallback = (...args: any[])=> any;
export interface CodeMirrorControl {
/** Points to a CodeMirror 6 EditorView instance. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
editor: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
cm6: any;
/** `extension` should be a [CodeMirror 6 extension](https://codemirror.net/docs/ref/#state.Extension). */
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
addExtension(extension: any|any[]): void;
supportsCommand(name: string): boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
execCommand(name: string, ...args: any[]): any;
registerCommand(name: string, callback: EditorCommandCallback): void;
joplinExtensions: {
/**
* Returns a [CodeMirror 6 extension](https://codemirror.net/docs/ref/#state.Extension) that
* registers the given [CompletionSource](https://codemirror.net/docs/ref/#autocomplete.CompletionSource).
*
* Use this extension rather than the built-in CodeMirror [`autocompletion`](https://codemirror.net/docs/ref/#autocomplete.autocompletion)
* if you don't want to use [languageData-based autocompletion](https://codemirror.net/docs/ref/#autocomplete.autocompletion^config.override).
*
* Using `autocompletion({ override: [ ... ]})` causes errors when done by multiple plugins.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
completionSource(completionSource: any): any;
/**
* Creates an extension that enables or disables [`languageData`-based autocompletion](https://codemirror.net/docs/ref/#autocomplete.autocompletion^config.override).
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
enableLanguageDataAutocomplete: { of: (enabled: boolean)=> any };
};
}
export interface MarkdownEditorContentScriptModule extends Omit<ContentScriptModule, 'plugin'> {
plugin: (editorControl: CodeMirrorControl)=> void;
}
export enum ContentScriptType {
/**
* Registers a new Markdown-It plugin, which should follow the template
@ -528,7 +625,7 @@ export enum ContentScriptType {
* module.exports = {
* default: function(context) {
* return {
* plugin: function(markdownIt, options) {
* plugin: function(markdownIt, pluginOptions) {
* // ...
* },
* assets: {
@ -538,6 +635,7 @@ export enum ContentScriptType {
* }
* }
* ```
*
* See [the
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* for a simple Markdown-it plugin example.
@ -550,10 +648,7 @@ export enum ContentScriptType {
*
* - The **required** `plugin` key is the actual Markdown-It plugin - check
* the [official doc](https://github.com/markdown-it/markdown-it) for more
* information. The `options` parameter is of type
* [RuleOptions](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml.ts),
* which contains a number of options, mostly useful for Joplin's internal
* code.
* information.
*
* - Using the **optional** `assets` key you may specify assets such as JS
* or CSS that should be loaded in the rendered HTML document. Check for
@ -561,6 +656,50 @@ export enum ContentScriptType {
* plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts)
* to see how the data should be structured.
*
* ## Supporting the Rich Text Editor
*
* Joplin's Rich Text Editor works with rendered HTML, which is converted back
* to markdown when saving. To prevent the original markdown for your plugin from
* being lost, Joplin needs additional metadata.
*
* To provide this,
* 1. Wrap the HTML generated by your plugin in an element with class `joplin-editable`.
* For example,
* ```html
* <div class="joplin-editable">
* ...your html...
* </div>
* ```
* 2. Add a child with class `joplin-source` that contains the original markdown that
* was rendered by your plugin. Include `data-joplin-source-open`, `data-joplin-source-close`,
* and `data-joplin-language` attributes.
* For example, if your plugin rendered the following code block,
* ````
* ```foo
* ... original source here ...
* ```
* ````
* then it should render to
* ```html
* <div class="joplin-editable">
* <pre
* class="joplin-source"
* data-joplin-language="foo"
* data-joplin-source-open="```foo&NewLine;"
* data-joplin-source-close="```"
* > ... original source here ... </pre>
* ... rendered HTML here ...
* </div>
* ```
*
* See [the demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* for a complete example.
*
* ## Getting the settings from the renderer
*
* You can access your plugin settings from the renderer by calling
* `pluginOptions.settingValue("your-setting-key')`.
*
* ## Posting messages from the content script to your plugin
*
* The application provides the following function to allow executing
@ -630,21 +769,21 @@ export enum ContentScriptType {
* }
* ```
*
* - The `context` argument is currently unused but could be used later on
* to provide access to your own plugin so that the content script and
* plugin can communicate.
* - The `context` argument allows communicating with other parts of
* your plugin (see below).
*
* - The `plugin` key is your CodeMirror plugin. This is where you can
* register new commands with CodeMirror or interact with the CodeMirror
* instance as needed.
*
* - The `codeMirrorResources` key is an array of CodeMirror resources that
* - **CodeMirror 5 only**: The `codeMirrorResources` key is an array of CodeMirror resources that
* will be loaded and attached to the CodeMirror module. These are made up
* of addons, keymaps, and modes. For example, for a plugin that want's to
* enable clojure highlighting in code blocks. `codeMirrorResources` would
* be set to `['mode/clojure/clojure']`.
* This field is ignored on mobile and when the desktop beta editor is enabled.
*
* - The `codeMirrorOptions` key contains all the
* - **CodeMirror 5 only**: The `codeMirrorOptions` key contains all the
* [CodeMirror](https://codemirror.net/doc/manual.html#config) options
* that will be set or changed by this plugin. New options can alse be
* declared via
@ -662,9 +801,11 @@ export enum ContentScriptType {
* must be provided for the plugin to be valid. Having multiple or all
* provided is also okay.
*
* See also the [demo
* plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* for an example of all these keys being used in one plugin.
* See also:
* - The [demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* for an example of all these keys being used in one plugin.
* - See [the editor plugin tutorial](https://joplinapp.org/help/api/tutorials/cm6_plugin)
* for how to develop a plugin for the mobile editor and the desktop beta markdown editor.
*
* ## Posting messages from the content script to your plugin
*

View File

@ -68,6 +68,8 @@ export default class Joplin {
* - [fs-extra](https://www.npmjs.com/package/fs-extra)
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/nativeModule)
*
* <span class="platform-desktop">desktop</span>
*/
require(_path: string): any;
versionInfo(): Promise<import("./types").VersionInfo>;

View File

@ -4,14 +4,20 @@ export default class JoplinClipboard {
constructor(electronClipboard: any, electronNativeImage: any);
readText(): Promise<string>;
writeText(text: string): Promise<void>;
/** <span class="platform-desktop">desktop</span> */
readHtml(): Promise<string>;
/** <span class="platform-desktop">desktop</span> */
writeHtml(html: string): Promise<void>;
/**
* Returns the image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
*
* <span class="platform-desktop">desktop</span>
*/
readImage(): Promise<string>;
/**
* Takes an image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
*
* <span class="platform-desktop">desktop</span>
*/
writeImage(dataUrl: string): Promise<void>;
/**

View File

@ -1,4 +1,5 @@
import { Command } from './types';
import Plugin from '../Plugin';
/**
* This class allows executing or registering new Joplin commands. Commands
* can be executed or associated with
@ -20,6 +21,12 @@ import { Command } from './types';
* To view what arguments are supported, you can open any of these files
* and look at the `execute()` command.
*
* Note that many of these commands only work on desktop. The more limited list of mobile
* commands can be found in these places:
*
* * [Global commands](https://github.com/laurent22/joplin/tree/dev/packages/app-mobile/commands)
* * [Editor commands](https://github.com/laurent22/joplin/blob/dev/packages/app-mobile/components/NoteEditor/commandDeclarations.ts)
*
* ## Executing editor commands
*
* There might be a situation where you want to invoke editor commands
@ -49,9 +56,10 @@ import { Command } from './types';
*
*/
export default class JoplinCommands {
private plugin_;
constructor(plugin_: Plugin);
/**
* <span class="platform-desktop">desktop</span> Executes the given
* command.
* Executes the given command.
*
* The command can take any number of arguments, and the supported
* arguments will vary based on the command. For custom commands, this
@ -70,7 +78,7 @@ export default class JoplinCommands {
*/
execute(commandName: string, ...args: any[]): Promise<any | void>;
/**
* <span class="platform-desktop">desktop</span> Registers a new command.
* Registers a new command.
*
* ```typescript
* // Register a new commmand called "testCommand1"

View File

@ -21,7 +21,8 @@ export default class JoplinContentScripts {
* for more information.
*
* * [View the renderer demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* * [View the editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* * [View the editor plugin tutorial](https://joplinapp.org/help/api/tutorials/cm6_plugin)
* * [View the legacy editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
*
* See also the [postMessage demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*

View File

@ -13,7 +13,7 @@ import { Path } from './types';
* In general you would use the methods in this class as if you were using a REST API. There are four methods that map to GET, POST, PUT and DELETE calls.
* And each method takes these parameters:
*
* * `path`: This is an array that represents the path to the resource in the form `["resouceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
* * `path`: This is an array that represents the path to the resource in the form `["resourceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
* * `query`: (Optional) The query parameters. In a URL, this is the part after the question mark "?". In this case, it should be an object with key/value pairs.
* * `data`: (Optional) Applies to PUT and POST calls only. The request body contains the data you want to create or modify, for example the content of a note or folder.
* * `files`: (Optional) Used to create new resources and associate them with files.

View File

@ -1,3 +1,4 @@
import { FilterHandler } from '../../../eventManager';
/**
* @ignore
*
@ -5,6 +6,6 @@
* so for now disable filters.
*/
export default class JoplinFilters {
on(name: string, callback: Function): Promise<void>;
off(name: string, callback: Function): Promise<void>;
on(name: string, callback: FilterHandler): Promise<void>;
off(name: string, callback: FilterHandler): Promise<void>;
}

View File

@ -1,12 +1,33 @@
import { Rectangle } from './types';
export interface Implementation {
nativeImage: any;
}
export interface CreateFromBufferOptions {
width?: number;
height?: number;
scaleFactor?: number;
}
export interface CreateFromPdfOptions {
/**
* The first page to export. Defaults to `1`, the first page in
* the document.
*/
minPage?: number;
/**
* The number of the last page to convert. Defaults to the last page
* if not given.
*
* If `maxPage` is greater than the number of pages in the PDF, all pages
* in the PDF will be converted to images.
*/
maxPage?: number;
scaleFactor?: number;
}
export interface PdfInfo {
pageCount: number;
}
export interface Implementation {
createFromPath: (path: string) => Promise<unknown>;
createFromPdf: (path: string, options: CreateFromPdfOptions) => Promise<unknown[]>;
getPdfInfo: (path: string) => Promise<PdfInfo>;
}
export interface ResizeOptions {
width?: number;
height?: number;
@ -24,6 +45,7 @@ export type Handle = string;
* [View the
* example](https://github.com/laurent22/joplin/blob/dev/packages/app-cli/tests/support/plugins/imaging/src/index.ts)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinImaging {
private implementation_;
@ -32,11 +54,20 @@ export default class JoplinImaging {
private createImageHandle;
private imageByHandle;
private cacheImage;
/**
* Creates an image from the provided path. Note that images and PDFs are supported. If you
* provide a URL instead of a local path, the file will be downloaded first then converted to an
* image.
*/
createFromPath(filePath: string): Promise<Handle>;
createFromResource(resourceId: string): Promise<Handle>;
createFromPdfPath(path: string, options?: CreateFromPdfOptions): Promise<Handle[]>;
createFromPdfResource(resourceId: string, options?: CreateFromPdfOptions): Promise<Handle[]>;
getPdfInfoFromPath(path: string): Promise<PdfInfo>;
getPdfInfoFromResource(resourceId: string): Promise<PdfInfo>;
getSize(handle: Handle): Promise<any>;
resize(handle: Handle, options?: ResizeOptions): Promise<string>;
crop(handle: Handle, rectange: Rectangle): Promise<string>;
crop(handle: Handle, rectangle: Rectangle): Promise<string>;
toPngFile(handle: Handle, filePath: string): Promise<void>;
/**
* Quality is between 0 and 100
@ -57,5 +88,5 @@ export default class JoplinImaging {
* Image data is not automatically deleted by Joplin so make sure you call
* this method on the handle once you are done.
*/
free(handle: Handle): Promise<void>;
free(handles: Handle[] | Handle): Promise<void>;
}

View File

@ -10,6 +10,9 @@ import { ExportModule, ImportModule } from './types';
* See the documentation of the [[ExportModule]] and [[ImportModule]] for more information.
*
* You may also want to refer to the Joplin API documentation to see the list of properties for each item (note, notebook, etc.) - https://joplinapp.org/help/api/references/rest_api
*
* <span class="platform-desktop">desktop</span>: While it is possible to register import and export
* modules on mobile, there is no GUI to activate them.
*/
export default class JoplinInterop {
registerExportModule(module: ExportModule): Promise<void>;

View File

@ -7,7 +7,6 @@ export interface ChangeEvent {
keys: string[];
}
export type ChangeHandler = (event: ChangeEvent) => void;
export declare const namespacedKey: (pluginId: string, key: string) => string;
/**
* This API allows registering new settings and setting sections, as well as getting and setting settings. Once a setting has been registered it will appear in the config screen and be editable by the user.
*
@ -39,6 +38,12 @@ export default class JoplinSettings {
*/
registerSection(name: string, section: SettingSection): Promise<void>;
/**
* Gets setting values (only applies to setting you registered from your plugin)
*/
values(keys: string[] | string): Promise<Record<string, unknown>>;
/**
* @deprecated Use joplin.settings.values()
*
* Gets a setting value (only applies to setting you registered from your plugin)
*/
value(key: string): Promise<any>;

View File

@ -5,6 +5,7 @@ import JoplinViewsMenus from './JoplinViewsMenus';
import JoplinViewsToolbarButtons from './JoplinViewsToolbarButtons';
import JoplinViewsPanels from './JoplinViewsPanels';
import JoplinViewsNoteList from './JoplinViewsNoteList';
import JoplinViewsEditors from './JoplinViewsEditor';
/**
* This namespace provides access to view-related services.
*
@ -19,11 +20,13 @@ export default class JoplinViews {
private menus_;
private toolbarButtons_;
private dialogs_;
private editors_;
private noteList_;
private implementation_;
constructor(implementation: any, plugin: Plugin, store: any);
get dialogs(): JoplinViewsDialogs;
get panels(): JoplinViewsPanels;
get editors(): JoplinViewsEditors;
get menuItems(): JoplinViewsMenuItems;
get menus(): JoplinViewsMenus;
get toolbarButtons(): JoplinViewsToolbarButtons;

View File

@ -47,6 +47,8 @@ export default class JoplinViewsDialogs {
* Displays a dialog to select a file or a directory. Same options and
* output as
* https://www.electronjs.org/docs/latest/api/dialog#dialogshowopendialogbrowserwindow-options
*
* <span class="platform-desktop">desktop</span>
*/
showOpenDialog(options: any): Promise<any>;
/**
@ -62,7 +64,9 @@ export default class JoplinViewsDialogs {
*/
setButtons(handle: ViewHandle, buttons: ButtonSpec[]): Promise<ButtonSpec[]>;
/**
* Opens the dialog
* Opens the dialog.
*
* On desktop, this closes any copies of the dialog open in different windows.
*/
open(handle: ViewHandle): Promise<DialogResult>;
/**

View File

@ -0,0 +1,88 @@
import Plugin from '../Plugin';
import { ActivationCheckCallback, ViewHandle, UpdateCallback } from './types';
/**
* Allows creating alternative note editors. You can create a view to handle loading and saving the
* note, and do your own rendering.
*
* Although it may be used to implement an alternative text editor, the more common use case may be
* to render the note in a different, graphical way - for example displaying a graph, and
* saving/loading the graph data in the associated note. In that case, you would detect whether the
* current note contains graph data and, in this case, you'd display your viewer.
*
* Terminology: An editor is **active** when it can be used to edit the current note. Note that it
* doesn't necessarily mean that your editor is visible - it just means that the user has the option
* to switch to it (via the "toggle editor" button). A **visible** editor is active and is currently
* being displayed.
*
* To implement an editor you need to listen to two events:
*
* - `onActivationCheck`: This is a way for the app to know whether your editor should be active or
* not. Return `true` from this handler to activate your editor.
*
* - `onUpdate`: When this is called you should update your editor based on the current note
* content. Call `joplin.workspace.selectedNote()` to get the current note.
*
* - `showEditorPlugin` and `toggleEditorPlugin` commands. Additionally you can use these commands
* to display your editor via `joplin.commands.execute('showEditorPlugin')`. This is not always
* necessary since the user can switch to your editor using the "toggle editor" button, however
* you may want to programmatically display the editor in some cases - for example when creating a
* new note specific to your editor.
*
* Note that only one editor view can be active at a time. This is why it is important not to
* activate your view if it's not relevant to the current note. If more than one is active, it is
* undefined which editor is going to be used to display the note.
*
* For an example of editor plugin, see the [YesYouKan
* plugin](https://github.com/joplin/plugin-yesyoukan/blob/master/src/index.ts). In particular,
* check the logic around `onActivationCheck` and `onUpdate` since this is the entry points for
* using this API.
*/
export default class JoplinViewsEditors {
private store;
private plugin;
private activationCheckHandlers_;
constructor(plugin: Plugin, store: any);
private controller;
/**
* Creates a new editor view
*/
create(id: string): Promise<ViewHandle>;
/**
* Sets the editor HTML content
*/
setHtml(handle: ViewHandle, html: string): Promise<string>;
/**
* Adds and loads a new JS or CSS file into the panel.
*/
addScript(handle: ViewHandle, scriptPath: string): Promise<void>;
/**
* See [[JoplinViewPanels]]
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Emitted when the editor can potentially be activated - this for example when the current note
* is changed, or when the application is opened. At that point should can check the current
* note and decide whether your editor should be activated or not. If it should return `true`,
* otherwise return `false`.
*/
onActivationCheck(handle: ViewHandle, callback: ActivationCheckCallback): Promise<void>;
/**
* Emitted when the editor content should be updated. This for example when the currently
* selected note changes, or when the user makes the editor visible.
*/
onUpdate(handle: ViewHandle, callback: UpdateCallback): Promise<void>;
/**
* See [[JoplinViewPanels]]
*/
postMessage(handle: ViewHandle, message: any): void;
/**
* Tells whether the editor is active or not.
*/
isActive(handle: ViewHandle): Promise<boolean>;
/**
* Tells whether the editor is effectively visible or not. If the editor is inactive, this will
* return `false`. If the editor is active and the user has switched to it, it will return
* `true`. Otherwise it will return `false`.
*/
isVisible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -4,6 +4,8 @@ import Plugin from '../Plugin';
* Allows creating and managing menu items.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/register_command)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsMenuItems {
private store;

View File

@ -4,6 +4,8 @@ import Plugin from '../Plugin';
* Allows creating menus.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/menu)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsMenus {
private store;

View File

@ -7,14 +7,32 @@ import { ListRenderer } from './noteListType';
*
* The app provides the required dependencies whenever a note is updated - you
* process these dependencies, and return some props, which are then passed to
* your template and rendered. See [[[ListRenderer]]] for a detailed description
* your template and rendered. See [[ListRenderer]] for a detailed description
* of each property of the renderer.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/note_list_renderer)
* ## Reference
*
* The default list renderer is implemented using the same API, so it worth checking it too:
* * [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/note_list_renderer)
*
* [Default list renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultListRenderer.ts)
* * [Default simple renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultListRenderer.ts)
*
* * [Default detailed renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultMultiColumnsRenderer.ts)
*
* ## Screenshots:
*
* ### Top to bottom with title, date and body
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/TopToBottom.png"/>
*
* ### Left to right with thumbnails
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/LeftToRight_Thumbnails.png"/>
*
* ### Top to bottom with editable title
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/TopToBottom_Editable.png"/>
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsNoteList {
private plugin_;

View File

@ -1,12 +1,17 @@
import Plugin from '../Plugin';
import { ViewHandle } from './types';
/**
* Allows creating and managing view panels. View panels currently are
* displayed at the right of the sidebar and allows displaying any HTML
* content (within a webview) and update it in real-time. For example it
* Allows creating and managing view panels. View panels allow displaying any HTML
* content (within a webview) and updating it in real-time. For example it
* could be used to display a table of content for the active note, or
* display various metadata or graph.
*
* On desktop, view panels currently are displayed at the right of the sidebar, though can
* be moved with "View" > "Change application layout".
*
* On mobile, view panels are shown in a tabbed dialog that can be opened using a
* toolbar button.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/toc)
*/
export default class JoplinViewsPanels {
@ -75,4 +80,5 @@ export default class JoplinViewsPanels {
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
isActive(handle: ViewHandle): Promise<boolean>;
}

View File

@ -1,17 +1,14 @@
import Plugin from '../Plugin';
export interface Implementation {
injectCustomStyles(elementId: string, cssFilePath: string): Promise<void>;
}
export default class JoplinWindow {
private plugin_;
private store_;
private implementation_;
constructor(implementation: Implementation, plugin: Plugin, store: any);
constructor(_plugin: Plugin, store: any);
/**
* Loads a chrome CSS file. It will apply to the window UI elements, except
* for the note viewer. It is the same as the "Custom stylesheet for
* Joplin-wide app styles" setting. See the [Load CSS Demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/load_css)
* for an example.
*
* <span class="platform-desktop">desktop</span>
*/
loadChromeCssFile(filePath: string): Promise<void>;
/**
@ -19,6 +16,8 @@ export default class JoplinWindow {
* exported or printed note. It is the same as the "Custom stylesheet for
* rendered Markdown" setting. See the [Load CSS Demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/load_css)
* for an example.
*
* <span class="platform-desktop">desktop</span>
*/
loadNoteCssFile(filePath: string): Promise<void>;
}

View File

@ -1,9 +1,6 @@
import Plugin from '../Plugin';
import { FolderEntity } from '../../database/types';
import { Disposable, MenuItem } from './types';
export interface EditContextMenuFilterObject {
items: MenuItem[];
}
type FilterHandler<T> = (object: T) => Promise<void>;
import { Disposable, EditContextMenuFilterObject, FilterHandler } from './types';
declare enum ItemChangeEventType {
Create = 1,
Update = 2,
@ -13,15 +10,25 @@ interface ItemChangeEvent {
id: string;
event: ItemChangeEventType;
}
interface SyncStartEvent {
withErrors: boolean;
}
interface ResourceChangeEvent {
id: string;
}
type ItemChangeHandler = (event: ItemChangeEvent) => void;
type SyncStartHandler = (event: SyncStartEvent) => void;
type ResourceChangeHandler = (event: ResourceChangeEvent) => void;
interface NoteContentChangeEvent {
note: any;
}
interface NoteSelectionChangeEvent {
value: string[];
}
interface NoteAlarmTriggerEvent {
noteId: string;
}
interface SyncCompleteEvent {
withErrors: boolean;
}
type WorkspaceEventHandler<EventType> = (event: EventType) => void;
type ItemChangeHandler = WorkspaceEventHandler<ItemChangeEvent>;
type SyncStartHandler = () => void;
type ResourceChangeHandler = WorkspaceEventHandler<ResourceChangeEvent>;
/**
* The workspace service provides access to all the parts of Joplin that
* are being worked on - i.e. the currently selected notes or notebooks as
@ -32,16 +39,17 @@ type ResourceChangeHandler = (event: ResourceChangeEvent) => void;
*/
export default class JoplinWorkspace {
private store;
constructor(store: any);
private plugin;
constructor(plugin: Plugin, store: any);
/**
* Called when a new note or notes are selected.
*/
onNoteSelectionChange(callback: Function): Promise<Disposable>;
onNoteSelectionChange(callback: WorkspaceEventHandler<NoteSelectionChangeEvent>): Promise<Disposable>;
/**
* Called when the content of a note changes.
* @deprecated Use `onNoteChange()` instead, which is reliably triggered whenever the note content, or any note property changes.
*/
onNoteContentChange(callback: Function): Promise<void>;
onNoteContentChange(callback: WorkspaceEventHandler<NoteContentChangeEvent>): Promise<void>;
/**
* Called when the content of the current note changes.
*/
@ -54,7 +62,7 @@ export default class JoplinWorkspace {
/**
* Called when an alarm associated with a to-do is triggered.
*/
onNoteAlarmTrigger(handler: Function): Promise<Disposable>;
onNoteAlarmTrigger(handler: WorkspaceEventHandler<NoteAlarmTriggerEvent>): Promise<Disposable>;
/**
* Called when the synchronisation process is starting.
*/
@ -62,14 +70,16 @@ export default class JoplinWorkspace {
/**
* Called when the synchronisation process has finished.
*/
onSyncComplete(callback: Function): Promise<Disposable>;
onSyncComplete(callback: WorkspaceEventHandler<SyncCompleteEvent>): Promise<Disposable>;
/**
* Called just before the editor context menu is about to open. Allows
* adding items to it.
*
* <span class="platform-desktop">desktop</span>
*/
filterEditorContextMenu(handler: FilterHandler<EditContextMenuFilterObject>): void;
/**
* Gets the currently selected note
* Gets the currently selected note. Will be `null` if no note is selected.
*/
selectedNote(): Promise<any>;
/**

View File

@ -1,5 +1,5 @@
import { Size } from './types';
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_data' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.deleted_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_data' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.deleted_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
export declare enum ItemFlow {
TopToBottom = "topToBottom",
LeftToRight = "leftToRight"
@ -10,29 +10,30 @@ export interface OnChangeEvent {
value: any;
noteId: string;
}
export interface OnClickEvent {
elementId: string;
}
export type OnRenderNoteHandler = (props: any) => Promise<RenderNoteView>;
export type OnChangeHandler = (event: OnChangeEvent) => Promise<void>;
export type OnClickHandler = (event: OnClickEvent) => Promise<void>;
/**
* Most of these are the built-in note properties, such as `note.title`,
* `note.todo_completed`, etc.
* Most of these are the built-in note properties, such as `note.title`, `note.todo_completed`, etc.
* complemented with special properties such as `note.isWatched`, to know if a note is currently
* opened in the external editor, and `note.tags` to get the list tags associated with the note.
*
* Additionally, the `item.*` properties are specific to the rendered item. The
* most important being `item.selected`, which you can use to display the
* selected note in a different way.
* The `note.todoStatusText` property is a localised description of the to-do status (e.g.
* "to-do, incomplete"). If you include an `<input type='checkbox' ... />` for to-do items that would
* otherwise be unlabelled, consider adding `note.todoStatusText` as the checkbox's `aria-label`.
*
* Finally some special properties are provided to make it easier to render
* notes. In particular, if possible prefer `note.titleHtml` to `note.title`
* since some important processing has already been done on the string, such as
* handling the search highlighter and escaping. Since it's HTML and already
* escaped you would insert it using `{{{titleHtml}}}` (triple-mustache syntax,
* which disables escaping).
* ## Item properties
*
* `notes.tag` gives you the list of tags associated with the note.
*
* `note.isWatched` tells you if the note is currently opened in an external
* editor. In which case you would generally display some indicator.
* The `item.*` properties are specific to the rendered item. The most important being
* `item.selected`, which you can use to display the selected note in a different way.
*/
export type ListRendererDepependency = ListRendererDatabaseDependency | 'item.size.width' | 'item.size.height' | 'item.selected' | 'note.titleHtml' | 'note.isWatched' | 'note.tags';
export type ListRendererDependency = ListRendererDatabaseDependency | 'item.index' | 'item.selected' | 'item.size.height' | 'item.size.width' | 'note.folder.title' | 'note.isWatched' | 'note.tags' | 'note.todoStatusText' | 'note.titleHtml';
export type ListRendererItemValueTemplates = Record<string, string>;
export declare const columnNames: readonly ["note.folder.title", "note.is_todo", "note.latitude", "note.longitude", "note.source_url", "note.tags", "note.title", "note.todo_completed", "note.todo_due", "note.user_created_time", "note.user_updated_time"];
export type ColumnName = typeof columnNames[number];
export interface ListRenderer {
/**
* It must be unique to your plugin.
@ -44,10 +45,15 @@ export interface ListRenderer {
* height.
*/
flow: ItemFlow;
/**
* Whether the renderer supports multiple columns. Applies only when `flow`
* is `topToBottom`. Defaults to `false`.
*/
multiColumns?: boolean;
/**
* The size of each item must be specified in advance for performance
* reasons, and cannot be changed afterwards. If the item flow is top to
* bottom, you only need to specificy the item height (the width will be
* bottom, you only need to specify the item height (the width will be
* ignored).
*/
itemSize: Size;
@ -74,20 +80,97 @@ export interface ListRenderer {
* that you do not add more than what you need since there is a performance
* penalty for each property.
*/
dependencies: ListRendererDepependency[];
dependencies?: ListRendererDependency[];
headerTemplate?: string;
headerHeight?: number;
onHeaderClick?: OnClickHandler;
/**
* This is the HTML template that will be used to render the note list item.
* This is a [Mustache template](https://github.com/janl/mustache.js) and it
* will receive the variable you return from `onRenderNote` as tags. For
* example, if you return a property named `formattedDate` from
* `onRenderNote`, you can insert it in the template using `Created date:
* {{formattedDate}}`.
* This property is set differently depending on the `multiColumns` property.
*
* In order to get syntax highlighting working here, it's recommended
* installing an editor extension such as [es6-string-html VSCode
* ## If `multiColumns` is `false`
*
* There is only one column and the template is used to render the entire row.
*
* This is the HTML template that will be used to render the note list item. This is a [Mustache
* template](https://github.com/janl/mustache.js) and it will receive the variable you return
* from `onRenderNote` as tags. For example, if you return a property named `formattedDate` from
* `onRenderNote`, you can insert it in the template using `Created date: {{formattedDate}}`
*
* ## If `multiColumns` is `true`
*
* Since there is multiple columns, this template will be used to render each note property
* within the row. For example if the current columns are the Updated and Title properties, this
* template will be called once to render the updated time and a second time to render the
* title. To display the current property, the generic `value` property is provided - it will be
* replaced at runtime by the actual note property. To render something different depending on
* the note property, use `itemValueTemplate`. A minimal example would be
* `<span>{{value}}</span>` which will simply render the current property inside a span tag.
*
* In order to get syntax highlighting working here, it's recommended installing an editor
* extension such as [es6-string-html VSCode
* extension](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
*
* ## Default property rendering
*
* Certain properties are automatically rendered once inserted in the Mustache template. Those
* are in particular all the date-related fields, such as `note.user_updated_time` or
* `note.todo_completed`. Internally, those are timestamps in milliseconds, however when
* rendered we display them as date/time strings using the user's preferred time format. Another
* notable auto-rendered property is `note.title` which is going to include additional HTML,
* such as the search markers.
*
* If you do not want this default rendering behaviour, for example if you want to display the
* raw timestamps in milliseconds, you can simply return custom properties from
* `onRenderNote()`. For example:
*
* ```typescript
* onRenderNote: async (props: any) => {
* return {
* ...props,
* // Return the property under a different name
* updatedTimeMs: props.note.user_updated_time,
* }
* },
*
* itemTemplate: // html
* `
* <div>
* Raw timestamp: {{updatedTimeMs}} <!-- This is **not** auto-rendered ->
* Formatted time: {{note.user_updated_time}} <!-- This is -->
* </div>
* `,
*
* ```
*
* See
* `[https://github.com/laurent22/joplin/blob/dev/packages/lib/services/noteList/renderViewProps.ts](renderViewProps.ts)`
* for the list of properties that have a default rendering.
*/
itemTemplate: string;
/**
* This property applies only when `multiColumns` is `true`. It is used to render something
* different for each note property.
*
* This is a map of actual dependencies to templates - you only need to return something if the
* default, as specified in `template`, is not enough.
*
* Again you need to return a Mustache template and it will be combined with the `template`
* property to create the final template. For example if you return a property named
* `formattedDate` from `onRenderNote`, you can insert it in the template using
* `{{formattedDate}}`. This string will replace `{{value}}` in the `template` property.
*
* So if the template property is set to `<span>{{value}}</span>`, the final template will be
* `<span>{{formattedDate}}</span>`.
*
* The property would be set as so:
*
* ```javascript
* itemValueTemplates: {
* 'note.user_updated_time': '{{formattedDate}}',
* }
* ```
*/
itemValueTemplates?: ListRendererItemValueTemplates;
/**
* This user-facing text is used for example in the View menu, so that your
* renderer can be selected.
@ -128,17 +211,15 @@ export interface ListRenderer {
*/
onRenderNote: OnRenderNoteHandler;
/**
* This handler allows adding some interacivity to the note renderer -
* whenever an input element within the item is changed (for example, when a
* checkbox is clicked, or a text input is changed), this `onChange` handler
* is going to be called.
* This handler allows adding some interactivity to the note renderer - whenever an input element
* within the item is changed (for example, when a checkbox is clicked, or a text input is
* changed), this `onChange` handler is going to be called.
*
* You can inspect `event.elementId` to know which element had some changes,
* and `event.value` to know the new value. `event.noteId` also tells you
* what note is affected, so that you can potentially apply changes to it.
* You can inspect `event.elementId` to know which element had some changes, and `event.value`
* to know the new value. `event.noteId` also tells you what note is affected, so that you can
* potentially apply changes to it.
*
* You specify the element ID, by setting a `data-id` attribute on the
* input.
* You specify the element ID, by setting a `data-id` attribute on the input.
*
* For example, if you have such a template:
*
@ -148,9 +229,26 @@ export interface ListRenderer {
* </div>
* ```
*
* The event handler will receive an event with `elementId` set to
* `noteTitleInput`.
* The event handler will receive an event with `elementId` set to `noteTitleInput`.
*
* ## Default event handlers
*
* Currently one click event is automatically handled:
*
* If there is a checkbox with a `data-id="todo-checkbox"` attribute is present, it is going to
* automatically toggle the note to-do "completed" status.
*
* For example this is what is used in the default list renderer:
*
* `<input data-id="todo-checkbox" type="checkbox" {{#note.todo_completed}}checked="checked"{{/note.todo_completed}}>`
*/
onChange?: OnChangeHandler;
}
export interface NoteListColumn {
name: ColumnName;
width: number;
}
export type NoteListColumns = NoteListColumn[];
export declare const defaultWidth = 100;
export declare const defaultListColumns: () => NoteListColumns;
export {};

View File

@ -3,7 +3,7 @@
import { Size } from './types';
// AUTO-GENERATED by generate-database-type
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_data' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.deleted_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_data' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.deleted_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
// AUTO-GENERATED by generate-database-type
export enum ItemFlow {
@ -11,45 +11,68 @@ export enum ItemFlow {
LeftToRight = 'leftToRight',
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export type RenderNoteView = Record<string, any>;
export interface OnChangeEvent {
elementId: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value: any;
noteId: string;
}
export interface OnClickEvent {
elementId: string;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export type OnRenderNoteHandler = (props: any)=> Promise<RenderNoteView>;
export type OnChangeHandler = (event: OnChangeEvent)=> Promise<void>;
export type OnClickHandler = (event: OnClickEvent)=> Promise<void>;
/**
* Most of these are the built-in note properties, such as `note.title`,
* `note.todo_completed`, etc.
* Most of these are the built-in note properties, such as `note.title`, `note.todo_completed`, etc.
* complemented with special properties such as `note.isWatched`, to know if a note is currently
* opened in the external editor, and `note.tags` to get the list tags associated with the note.
*
* Additionally, the `item.*` properties are specific to the rendered item. The
* most important being `item.selected`, which you can use to display the
* selected note in a different way.
* The `note.todoStatusText` property is a localised description of the to-do status (e.g.
* "to-do, incomplete"). If you include an `<input type='checkbox' ... />` for to-do items that would
* otherwise be unlabelled, consider adding `note.todoStatusText` as the checkbox's `aria-label`.
*
* Finally some special properties are provided to make it easier to render
* notes. In particular, if possible prefer `note.titleHtml` to `note.title`
* since some important processing has already been done on the string, such as
* handling the search highlighter and escaping. Since it's HTML and already
* escaped you would insert it using `{{{titleHtml}}}` (triple-mustache syntax,
* which disables escaping).
* ## Item properties
*
* `notes.tag` gives you the list of tags associated with the note.
*
* `note.isWatched` tells you if the note is currently opened in an external
* editor. In which case you would generally display some indicator.
* The `item.*` properties are specific to the rendered item. The most important being
* `item.selected`, which you can use to display the selected note in a different way.
*/
export type ListRendererDepependency =
export type ListRendererDependency =
ListRendererDatabaseDependency |
'item.size.width' |
'item.size.height' |
'item.index' |
'item.selected' |
'note.titleHtml' |
'item.size.height' |
'item.size.width' |
'note.folder.title' |
'note.isWatched' |
'note.tags';
'note.tags' |
'note.todoStatusText' |
'note.titleHtml';
export type ListRendererItemValueTemplates = Record<string, string>;
export const columnNames = [
'note.folder.title',
'note.is_todo',
'note.latitude',
'note.longitude',
'note.source_url',
'note.tags',
'note.title',
'note.todo_completed',
'note.todo_due',
'note.user_created_time',
'note.user_updated_time',
] as const;
export type ColumnName = typeof columnNames[number];
export interface ListRenderer {
/**
@ -64,10 +87,16 @@ export interface ListRenderer {
*/
flow: ItemFlow;
/**
* Whether the renderer supports multiple columns. Applies only when `flow`
* is `topToBottom`. Defaults to `false`.
*/
multiColumns?: boolean;
/**
* The size of each item must be specified in advance for performance
* reasons, and cannot be changed afterwards. If the item flow is top to
* bottom, you only need to specificy the item height (the width will be
* bottom, you only need to specify the item height (the width will be
* ignored).
*/
itemSize: Size;
@ -96,22 +125,101 @@ export interface ListRenderer {
* that you do not add more than what you need since there is a performance
* penalty for each property.
*/
dependencies: ListRendererDepependency[];
dependencies?: ListRendererDependency[];
headerTemplate?: string;
headerHeight?: number;
onHeaderClick?: OnClickHandler;
/**
* This is the HTML template that will be used to render the note list item.
* This is a [Mustache template](https://github.com/janl/mustache.js) and it
* will receive the variable you return from `onRenderNote` as tags. For
* example, if you return a property named `formattedDate` from
* `onRenderNote`, you can insert it in the template using `Created date:
* {{formattedDate}}`.
* This property is set differently depending on the `multiColumns` property.
*
* In order to get syntax highlighting working here, it's recommended
* installing an editor extension such as [es6-string-html VSCode
* ## If `multiColumns` is `false`
*
* There is only one column and the template is used to render the entire row.
*
* This is the HTML template that will be used to render the note list item. This is a [Mustache
* template](https://github.com/janl/mustache.js) and it will receive the variable you return
* from `onRenderNote` as tags. For example, if you return a property named `formattedDate` from
* `onRenderNote`, you can insert it in the template using `Created date: {{formattedDate}}`
*
* ## If `multiColumns` is `true`
*
* Since there is multiple columns, this template will be used to render each note property
* within the row. For example if the current columns are the Updated and Title properties, this
* template will be called once to render the updated time and a second time to render the
* title. To display the current property, the generic `value` property is provided - it will be
* replaced at runtime by the actual note property. To render something different depending on
* the note property, use `itemValueTemplate`. A minimal example would be
* `<span>{{value}}</span>` which will simply render the current property inside a span tag.
*
* In order to get syntax highlighting working here, it's recommended installing an editor
* extension such as [es6-string-html VSCode
* extension](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
*
* ## Default property rendering
*
* Certain properties are automatically rendered once inserted in the Mustache template. Those
* are in particular all the date-related fields, such as `note.user_updated_time` or
* `note.todo_completed`. Internally, those are timestamps in milliseconds, however when
* rendered we display them as date/time strings using the user's preferred time format. Another
* notable auto-rendered property is `note.title` which is going to include additional HTML,
* such as the search markers.
*
* If you do not want this default rendering behaviour, for example if you want to display the
* raw timestamps in milliseconds, you can simply return custom properties from
* `onRenderNote()`. For example:
*
* ```typescript
* onRenderNote: async (props: any) => {
* return {
* ...props,
* // Return the property under a different name
* updatedTimeMs: props.note.user_updated_time,
* }
* },
*
* itemTemplate: // html
* `
* <div>
* Raw timestamp: {{updatedTimeMs}} <!-- This is **not** auto-rendered ->
* Formatted time: {{note.user_updated_time}} <!-- This is -->
* </div>
* `,
*
* ```
*
* See
* `[https://github.com/laurent22/joplin/blob/dev/packages/lib/services/noteList/renderViewProps.ts](renderViewProps.ts)`
* for the list of properties that have a default rendering.
*/
itemTemplate: string;
/**
* This property applies only when `multiColumns` is `true`. It is used to render something
* different for each note property.
*
* This is a map of actual dependencies to templates - you only need to return something if the
* default, as specified in `template`, is not enough.
*
* Again you need to return a Mustache template and it will be combined with the `template`
* property to create the final template. For example if you return a property named
* `formattedDate` from `onRenderNote`, you can insert it in the template using
* `{{formattedDate}}`. This string will replace `{{value}}` in the `template` property.
*
* So if the template property is set to `<span>{{value}}</span>`, the final template will be
* `<span>{{formattedDate}}</span>`.
*
* The property would be set as so:
*
* ```javascript
* itemValueTemplates: {
* 'note.user_updated_time': '{{formattedDate}}',
* }
* ```
*/
itemValueTemplates?: ListRendererItemValueTemplates;
/**
* This user-facing text is used for example in the View menu, so that your
* renderer can be selected.
@ -154,17 +262,15 @@ export interface ListRenderer {
onRenderNote: OnRenderNoteHandler;
/**
* This handler allows adding some interacivity to the note renderer -
* whenever an input element within the item is changed (for example, when a
* checkbox is clicked, or a text input is changed), this `onChange` handler
* is going to be called.
* This handler allows adding some interactivity to the note renderer - whenever an input element
* within the item is changed (for example, when a checkbox is clicked, or a text input is
* changed), this `onChange` handler is going to be called.
*
* You can inspect `event.elementId` to know which element had some changes,
* and `event.value` to know the new value. `event.noteId` also tells you
* what note is affected, so that you can potentially apply changes to it.
* You can inspect `event.elementId` to know which element had some changes, and `event.value`
* to know the new value. `event.noteId` also tells you what note is affected, so that you can
* potentially apply changes to it.
*
* You specify the element ID, by setting a `data-id` attribute on the
* input.
* You specify the element ID, by setting a `data-id` attribute on the input.
*
* For example, if you have such a template:
*
@ -174,8 +280,46 @@ export interface ListRenderer {
* </div>
* ```
*
* The event handler will receive an event with `elementId` set to
* `noteTitleInput`.
* The event handler will receive an event with `elementId` set to `noteTitleInput`.
*
* ## Default event handlers
*
* Currently one click event is automatically handled:
*
* If there is a checkbox with a `data-id="todo-checkbox"` attribute is present, it is going to
* automatically toggle the note to-do "completed" status.
*
* For example this is what is used in the default list renderer:
*
* `<input data-id="todo-checkbox" type="checkbox" {{#note.todo_completed}}checked="checked"{{/note.todo_completed}}>`
*/
onChange?: OnChangeHandler;
}
export interface NoteListColumn {
name: ColumnName;
width: number;
}
export type NoteListColumns = NoteListColumn[];
export const defaultWidth = 100;
export const defaultListColumns = () => {
const columns: NoteListColumns = [
{
name: 'note.is_todo',
width: 30,
},
{
name: 'note.user_updated_time',
width: defaultWidth,
},
{
name: 'note.title',
width: 0,
},
];
return columns;
};

View File

@ -26,6 +26,7 @@ export interface Command {
/**
* Code to be ran when the command is executed. It may return a result.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
execute(...args: any[]): Promise<any | void>;
/**
@ -115,11 +116,13 @@ export interface ExportModule {
/**
* Called when an item needs to be processed. An "item" can be any Joplin object, such as a note, a folder, a notebook, etc.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onProcessItem(context: ExportContext, itemType: number, item: any): Promise<void>;
/**
* Called when a resource file needs to be exported.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onProcessResource(context: ExportContext, resource: any, filePath: string): Promise<void>;
/**
@ -181,13 +184,15 @@ export interface ExportContext {
options: ExportOptions;
/**
* You can attach your own custom data using this propery - it will then be passed to each event handler, allowing you to keep state from one event to the next.
* You can attach your own custom data using this property - it will then be passed to each event handler, allowing you to keep state from one event to the next.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
userData?: any;
}
export interface ImportContext {
sourcePath: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
options: any;
warnings: string[];
}
@ -197,6 +202,7 @@ export interface ImportContext {
// =================================================================
export interface Script {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onStart?(event: any): Promise<void>;
}
@ -227,6 +233,8 @@ export interface VersionInfo {
version: string;
profileVersion: number;
syncVersion: number;
platform: 'desktop'|'mobile';
}
// =================================================================
@ -300,6 +308,7 @@ export interface MenuItem {
* Arguments that should be passed to the command. They will be as rest
* parameters.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
commandArgs?: any[];
/**
@ -338,6 +347,8 @@ export type ButtonId = string;
export enum ToolbarButtonLocation {
/**
* This toolbar in the top right corner of the application. It applies to the note as a whole, including its metadata.
*
* <span class="platform-desktop">desktop</span>
*/
NoteToolbar = 'noteToolbar',
@ -351,11 +362,13 @@ export type ViewHandle = string;
export interface EditorCommand {
name: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value?: any;
}
export interface DialogResult {
id: ButtonId;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
formData?: any;
}
@ -371,6 +384,26 @@ export interface Rectangle {
height?: number;
}
export type ActivationCheckCallback = ()=> Promise<boolean>;
export type UpdateCallback = ()=> Promise<void>;
export type VisibleHandler = ()=> Promise<void>;
export interface EditContextMenuFilterObject {
items: MenuItem[];
}
export interface EditorActivationCheckFilterObject {
activatedEditors: {
pluginId: string;
viewId: string;
isActive: boolean;
}[];
}
export type FilterHandler<T> = (object: T)=> Promise<T>;
// =================================================================
// Settings types
// =================================================================
@ -404,6 +437,7 @@ export enum SettingStorage {
// Redefine a simplified interface to mask internal details
// and to remove function calls as they would have to be async.
export interface SettingItem {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value: any;
type: SettingItemType;
@ -440,6 +474,7 @@ export interface SettingItem {
* This property is required when `isEnum` is `true`. In which case, it
* should contain a map of value => label.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
options?: Record<any, any>;
/**
@ -497,6 +532,7 @@ export type Path = string[];
// Content Script types
// =================================================================
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export type PostMessageHandler = (message: any)=> Promise<any>;
/**
@ -520,19 +556,66 @@ export interface ContentScriptContext {
}
export interface ContentScriptModuleLoadedEvent {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
userData?: any;
}
export interface ContentScriptModule {
onLoaded?: (event: ContentScriptModuleLoadedEvent)=> void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
plugin: ()=> any;
assets?: ()=> void;
}
export interface MarkdownItContentScriptModule extends Omit<ContentScriptModule, 'plugin'> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
plugin: (markdownIt: any, options: any)=> any;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
type EditorCommandCallback = (...args: any[])=> any;
export interface CodeMirrorControl {
/** Points to a CodeMirror 6 EditorView instance. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
editor: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
cm6: any;
/** `extension` should be a [CodeMirror 6 extension](https://codemirror.net/docs/ref/#state.Extension). */
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
addExtension(extension: any|any[]): void;
supportsCommand(name: string): boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
execCommand(name: string, ...args: any[]): any;
registerCommand(name: string, callback: EditorCommandCallback): void;
joplinExtensions: {
/**
* Returns a [CodeMirror 6 extension](https://codemirror.net/docs/ref/#state.Extension) that
* registers the given [CompletionSource](https://codemirror.net/docs/ref/#autocomplete.CompletionSource).
*
* Use this extension rather than the built-in CodeMirror [`autocompletion`](https://codemirror.net/docs/ref/#autocomplete.autocompletion)
* if you don't want to use [languageData-based autocompletion](https://codemirror.net/docs/ref/#autocomplete.autocompletion^config.override).
*
* Using `autocompletion({ override: [ ... ]})` causes errors when done by multiple plugins.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
completionSource(completionSource: any): any;
/**
* Creates an extension that enables or disables [`languageData`-based autocompletion](https://codemirror.net/docs/ref/#autocomplete.autocompletion^config.override).
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
enableLanguageDataAutocomplete: { of: (enabled: boolean)=> any };
};
}
export interface MarkdownEditorContentScriptModule extends Omit<ContentScriptModule, 'plugin'> {
plugin: (editorControl: CodeMirrorControl)=> void;
}
export enum ContentScriptType {
/**
* Registers a new Markdown-It plugin, which should follow the template
@ -573,6 +656,45 @@ export enum ContentScriptType {
* plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts)
* to see how the data should be structured.
*
* ## Supporting the Rich Text Editor
*
* Joplin's Rich Text Editor works with rendered HTML, which is converted back
* to markdown when saving. To prevent the original markdown for your plugin from
* being lost, Joplin needs additional metadata.
*
* To provide this,
* 1. Wrap the HTML generated by your plugin in an element with class `joplin-editable`.
* For example,
* ```html
* <div class="joplin-editable">
* ...your html...
* </div>
* ```
* 2. Add a child with class `joplin-source` that contains the original markdown that
* was rendered by your plugin. Include `data-joplin-source-open`, `data-joplin-source-close`,
* and `data-joplin-language` attributes.
* For example, if your plugin rendered the following code block,
* ````
* ```foo
* ... original source here ...
* ```
* ````
* then it should render to
* ```html
* <div class="joplin-editable">
* <pre
* class="joplin-source"
* data-joplin-language="foo"
* data-joplin-source-open="```foo&NewLine;"
* data-joplin-source-close="```"
* > ... original source here ... </pre>
* ... rendered HTML here ...
* </div>
* ```
*
* See [the demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* for a complete example.
*
* ## Getting the settings from the renderer
*
* You can access your plugin settings from the renderer by calling
@ -647,21 +769,21 @@ export enum ContentScriptType {
* }
* ```
*
* - The `context` argument is currently unused but could be used later on
* to provide access to your own plugin so that the content script and
* plugin can communicate.
* - The `context` argument allows communicating with other parts of
* your plugin (see below).
*
* - The `plugin` key is your CodeMirror plugin. This is where you can
* register new commands with CodeMirror or interact with the CodeMirror
* instance as needed.
*
* - The `codeMirrorResources` key is an array of CodeMirror resources that
* - **CodeMirror 5 only**: The `codeMirrorResources` key is an array of CodeMirror resources that
* will be loaded and attached to the CodeMirror module. These are made up
* of addons, keymaps, and modes. For example, for a plugin that want's to
* enable clojure highlighting in code blocks. `codeMirrorResources` would
* be set to `['mode/clojure/clojure']`.
* This field is ignored on mobile and when the desktop beta editor is enabled.
*
* - The `codeMirrorOptions` key contains all the
* - **CodeMirror 5 only**: The `codeMirrorOptions` key contains all the
* [CodeMirror](https://codemirror.net/doc/manual.html#config) options
* that will be set or changed by this plugin. New options can alse be
* declared via
@ -679,9 +801,11 @@ export enum ContentScriptType {
* must be provided for the plugin to be valid. Having multiple or all
* provided is also okay.
*
* See also the [demo
* plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* for an example of all these keys being used in one plugin.
* See also:
* - The [demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* for an example of all these keys being used in one plugin.
* - See [the editor plugin tutorial](https://joplinapp.org/help/api/tutorials/cm6_plugin)
* for how to develop a plugin for the mobile editor and the desktop beta markdown editor.
*
* ## Posting messages from the content script to your plugin
*

View File

@ -68,6 +68,8 @@ export default class Joplin {
* - [fs-extra](https://www.npmjs.com/package/fs-extra)
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/nativeModule)
*
* <span class="platform-desktop">desktop</span>
*/
require(_path: string): any;
versionInfo(): Promise<import("./types").VersionInfo>;

View File

@ -4,14 +4,20 @@ export default class JoplinClipboard {
constructor(electronClipboard: any, electronNativeImage: any);
readText(): Promise<string>;
writeText(text: string): Promise<void>;
/** <span class="platform-desktop">desktop</span> */
readHtml(): Promise<string>;
/** <span class="platform-desktop">desktop</span> */
writeHtml(html: string): Promise<void>;
/**
* Returns the image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
*
* <span class="platform-desktop">desktop</span>
*/
readImage(): Promise<string>;
/**
* Takes an image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
*
* <span class="platform-desktop">desktop</span>
*/
writeImage(dataUrl: string): Promise<void>;
/**

View File

@ -1,4 +1,5 @@
import { Command } from './types';
import Plugin from '../Plugin';
/**
* This class allows executing or registering new Joplin commands. Commands
* can be executed or associated with
@ -20,6 +21,12 @@ import { Command } from './types';
* To view what arguments are supported, you can open any of these files
* and look at the `execute()` command.
*
* Note that many of these commands only work on desktop. The more limited list of mobile
* commands can be found in these places:
*
* * [Global commands](https://github.com/laurent22/joplin/tree/dev/packages/app-mobile/commands)
* * [Editor commands](https://github.com/laurent22/joplin/blob/dev/packages/app-mobile/components/NoteEditor/commandDeclarations.ts)
*
* ## Executing editor commands
*
* There might be a situation where you want to invoke editor commands
@ -49,9 +56,10 @@ import { Command } from './types';
*
*/
export default class JoplinCommands {
private plugin_;
constructor(plugin_: Plugin);
/**
* <span class="platform-desktop">desktop</span> Executes the given
* command.
* Executes the given command.
*
* The command can take any number of arguments, and the supported
* arguments will vary based on the command. For custom commands, this
@ -70,7 +78,7 @@ export default class JoplinCommands {
*/
execute(commandName: string, ...args: any[]): Promise<any | void>;
/**
* <span class="platform-desktop">desktop</span> Registers a new command.
* Registers a new command.
*
* ```typescript
* // Register a new commmand called "testCommand1"

View File

@ -21,7 +21,8 @@ export default class JoplinContentScripts {
* for more information.
*
* * [View the renderer demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* * [View the editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* * [View the editor plugin tutorial](https://joplinapp.org/help/api/tutorials/cm6_plugin)
* * [View the legacy editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
*
* See also the [postMessage demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*

View File

@ -13,7 +13,7 @@ import { Path } from './types';
* In general you would use the methods in this class as if you were using a REST API. There are four methods that map to GET, POST, PUT and DELETE calls.
* And each method takes these parameters:
*
* * `path`: This is an array that represents the path to the resource in the form `["resouceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
* * `path`: This is an array that represents the path to the resource in the form `["resourceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
* * `query`: (Optional) The query parameters. In a URL, this is the part after the question mark "?". In this case, it should be an object with key/value pairs.
* * `data`: (Optional) Applies to PUT and POST calls only. The request body contains the data you want to create or modify, for example the content of a note or folder.
* * `files`: (Optional) Used to create new resources and associate them with files.

View File

@ -1,3 +1,4 @@
import { FilterHandler } from '../../../eventManager';
/**
* @ignore
*
@ -5,6 +6,6 @@
* so for now disable filters.
*/
export default class JoplinFilters {
on(name: string, callback: Function): Promise<void>;
off(name: string, callback: Function): Promise<void>;
on(name: string, callback: FilterHandler): Promise<void>;
off(name: string, callback: FilterHandler): Promise<void>;
}

View File

@ -1,12 +1,33 @@
import { Rectangle } from './types';
export interface Implementation {
nativeImage: any;
}
export interface CreateFromBufferOptions {
width?: number;
height?: number;
scaleFactor?: number;
}
export interface CreateFromPdfOptions {
/**
* The first page to export. Defaults to `1`, the first page in
* the document.
*/
minPage?: number;
/**
* The number of the last page to convert. Defaults to the last page
* if not given.
*
* If `maxPage` is greater than the number of pages in the PDF, all pages
* in the PDF will be converted to images.
*/
maxPage?: number;
scaleFactor?: number;
}
export interface PdfInfo {
pageCount: number;
}
export interface Implementation {
createFromPath: (path: string) => Promise<unknown>;
createFromPdf: (path: string, options: CreateFromPdfOptions) => Promise<unknown[]>;
getPdfInfo: (path: string) => Promise<PdfInfo>;
}
export interface ResizeOptions {
width?: number;
height?: number;
@ -24,6 +45,7 @@ export type Handle = string;
* [View the
* example](https://github.com/laurent22/joplin/blob/dev/packages/app-cli/tests/support/plugins/imaging/src/index.ts)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinImaging {
private implementation_;
@ -32,11 +54,20 @@ export default class JoplinImaging {
private createImageHandle;
private imageByHandle;
private cacheImage;
/**
* Creates an image from the provided path. Note that images and PDFs are supported. If you
* provide a URL instead of a local path, the file will be downloaded first then converted to an
* image.
*/
createFromPath(filePath: string): Promise<Handle>;
createFromResource(resourceId: string): Promise<Handle>;
createFromPdfPath(path: string, options?: CreateFromPdfOptions): Promise<Handle[]>;
createFromPdfResource(resourceId: string, options?: CreateFromPdfOptions): Promise<Handle[]>;
getPdfInfoFromPath(path: string): Promise<PdfInfo>;
getPdfInfoFromResource(resourceId: string): Promise<PdfInfo>;
getSize(handle: Handle): Promise<any>;
resize(handle: Handle, options?: ResizeOptions): Promise<string>;
crop(handle: Handle, rectange: Rectangle): Promise<string>;
crop(handle: Handle, rectangle: Rectangle): Promise<string>;
toPngFile(handle: Handle, filePath: string): Promise<void>;
/**
* Quality is between 0 and 100
@ -57,5 +88,5 @@ export default class JoplinImaging {
* Image data is not automatically deleted by Joplin so make sure you call
* this method on the handle once you are done.
*/
free(handle: Handle): Promise<void>;
free(handles: Handle[] | Handle): Promise<void>;
}

View File

@ -10,6 +10,9 @@ import { ExportModule, ImportModule } from './types';
* See the documentation of the [[ExportModule]] and [[ImportModule]] for more information.
*
* You may also want to refer to the Joplin API documentation to see the list of properties for each item (note, notebook, etc.) - https://joplinapp.org/help/api/references/rest_api
*
* <span class="platform-desktop">desktop</span>: While it is possible to register import and export
* modules on mobile, there is no GUI to activate them.
*/
export default class JoplinInterop {
registerExportModule(module: ExportModule): Promise<void>;

View File

@ -7,7 +7,6 @@ export interface ChangeEvent {
keys: string[];
}
export type ChangeHandler = (event: ChangeEvent) => void;
export declare const namespacedKey: (pluginId: string, key: string) => string;
/**
* This API allows registering new settings and setting sections, as well as getting and setting settings. Once a setting has been registered it will appear in the config screen and be editable by the user.
*
@ -39,6 +38,12 @@ export default class JoplinSettings {
*/
registerSection(name: string, section: SettingSection): Promise<void>;
/**
* Gets setting values (only applies to setting you registered from your plugin)
*/
values(keys: string[] | string): Promise<Record<string, unknown>>;
/**
* @deprecated Use joplin.settings.values()
*
* Gets a setting value (only applies to setting you registered from your plugin)
*/
value(key: string): Promise<any>;

View File

@ -5,6 +5,7 @@ import JoplinViewsMenus from './JoplinViewsMenus';
import JoplinViewsToolbarButtons from './JoplinViewsToolbarButtons';
import JoplinViewsPanels from './JoplinViewsPanels';
import JoplinViewsNoteList from './JoplinViewsNoteList';
import JoplinViewsEditors from './JoplinViewsEditor';
/**
* This namespace provides access to view-related services.
*
@ -19,11 +20,13 @@ export default class JoplinViews {
private menus_;
private toolbarButtons_;
private dialogs_;
private editors_;
private noteList_;
private implementation_;
constructor(implementation: any, plugin: Plugin, store: any);
get dialogs(): JoplinViewsDialogs;
get panels(): JoplinViewsPanels;
get editors(): JoplinViewsEditors;
get menuItems(): JoplinViewsMenuItems;
get menus(): JoplinViewsMenus;
get toolbarButtons(): JoplinViewsToolbarButtons;

View File

@ -47,6 +47,8 @@ export default class JoplinViewsDialogs {
* Displays a dialog to select a file or a directory. Same options and
* output as
* https://www.electronjs.org/docs/latest/api/dialog#dialogshowopendialogbrowserwindow-options
*
* <span class="platform-desktop">desktop</span>
*/
showOpenDialog(options: any): Promise<any>;
/**
@ -62,7 +64,9 @@ export default class JoplinViewsDialogs {
*/
setButtons(handle: ViewHandle, buttons: ButtonSpec[]): Promise<ButtonSpec[]>;
/**
* Opens the dialog
* Opens the dialog.
*
* On desktop, this closes any copies of the dialog open in different windows.
*/
open(handle: ViewHandle): Promise<DialogResult>;
/**

View File

@ -0,0 +1,88 @@
import Plugin from '../Plugin';
import { ActivationCheckCallback, ViewHandle, UpdateCallback } from './types';
/**
* Allows creating alternative note editors. You can create a view to handle loading and saving the
* note, and do your own rendering.
*
* Although it may be used to implement an alternative text editor, the more common use case may be
* to render the note in a different, graphical way - for example displaying a graph, and
* saving/loading the graph data in the associated note. In that case, you would detect whether the
* current note contains graph data and, in this case, you'd display your viewer.
*
* Terminology: An editor is **active** when it can be used to edit the current note. Note that it
* doesn't necessarily mean that your editor is visible - it just means that the user has the option
* to switch to it (via the "toggle editor" button). A **visible** editor is active and is currently
* being displayed.
*
* To implement an editor you need to listen to two events:
*
* - `onActivationCheck`: This is a way for the app to know whether your editor should be active or
* not. Return `true` from this handler to activate your editor.
*
* - `onUpdate`: When this is called you should update your editor based on the current note
* content. Call `joplin.workspace.selectedNote()` to get the current note.
*
* - `showEditorPlugin` and `toggleEditorPlugin` commands. Additionally you can use these commands
* to display your editor via `joplin.commands.execute('showEditorPlugin')`. This is not always
* necessary since the user can switch to your editor using the "toggle editor" button, however
* you may want to programmatically display the editor in some cases - for example when creating a
* new note specific to your editor.
*
* Note that only one editor view can be active at a time. This is why it is important not to
* activate your view if it's not relevant to the current note. If more than one is active, it is
* undefined which editor is going to be used to display the note.
*
* For an example of editor plugin, see the [YesYouKan
* plugin](https://github.com/joplin/plugin-yesyoukan/blob/master/src/index.ts). In particular,
* check the logic around `onActivationCheck` and `onUpdate` since this is the entry points for
* using this API.
*/
export default class JoplinViewsEditors {
private store;
private plugin;
private activationCheckHandlers_;
constructor(plugin: Plugin, store: any);
private controller;
/**
* Creates a new editor view
*/
create(id: string): Promise<ViewHandle>;
/**
* Sets the editor HTML content
*/
setHtml(handle: ViewHandle, html: string): Promise<string>;
/**
* Adds and loads a new JS or CSS file into the panel.
*/
addScript(handle: ViewHandle, scriptPath: string): Promise<void>;
/**
* See [[JoplinViewPanels]]
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Emitted when the editor can potentially be activated - this for example when the current note
* is changed, or when the application is opened. At that point should can check the current
* note and decide whether your editor should be activated or not. If it should return `true`,
* otherwise return `false`.
*/
onActivationCheck(handle: ViewHandle, callback: ActivationCheckCallback): Promise<void>;
/**
* Emitted when the editor content should be updated. This for example when the currently
* selected note changes, or when the user makes the editor visible.
*/
onUpdate(handle: ViewHandle, callback: UpdateCallback): Promise<void>;
/**
* See [[JoplinViewPanels]]
*/
postMessage(handle: ViewHandle, message: any): void;
/**
* Tells whether the editor is active or not.
*/
isActive(handle: ViewHandle): Promise<boolean>;
/**
* Tells whether the editor is effectively visible or not. If the editor is inactive, this will
* return `false`. If the editor is active and the user has switched to it, it will return
* `true`. Otherwise it will return `false`.
*/
isVisible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -4,6 +4,8 @@ import Plugin from '../Plugin';
* Allows creating and managing menu items.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/register_command)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsMenuItems {
private store;

View File

@ -4,6 +4,8 @@ import Plugin from '../Plugin';
* Allows creating menus.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/menu)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsMenus {
private store;

View File

@ -7,14 +7,32 @@ import { ListRenderer } from './noteListType';
*
* The app provides the required dependencies whenever a note is updated - you
* process these dependencies, and return some props, which are then passed to
* your template and rendered. See [[[ListRenderer]]] for a detailed description
* your template and rendered. See [[ListRenderer]] for a detailed description
* of each property of the renderer.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/note_list_renderer)
* ## Reference
*
* The default list renderer is implemented using the same API, so it worth checking it too:
* * [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/note_list_renderer)
*
* [Default list renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultListRenderer.ts)
* * [Default simple renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultListRenderer.ts)
*
* * [Default detailed renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultMultiColumnsRenderer.ts)
*
* ## Screenshots:
*
* ### Top to bottom with title, date and body
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/TopToBottom.png"/>
*
* ### Left to right with thumbnails
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/LeftToRight_Thumbnails.png"/>
*
* ### Top to bottom with editable title
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/TopToBottom_Editable.png"/>
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsNoteList {
private plugin_;

View File

@ -1,12 +1,17 @@
import Plugin from '../Plugin';
import { ViewHandle } from './types';
/**
* Allows creating and managing view panels. View panels currently are
* displayed at the right of the sidebar and allows displaying any HTML
* content (within a webview) and update it in real-time. For example it
* Allows creating and managing view panels. View panels allow displaying any HTML
* content (within a webview) and updating it in real-time. For example it
* could be used to display a table of content for the active note, or
* display various metadata or graph.
*
* On desktop, view panels currently are displayed at the right of the sidebar, though can
* be moved with "View" > "Change application layout".
*
* On mobile, view panels are shown in a tabbed dialog that can be opened using a
* toolbar button.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/toc)
*/
export default class JoplinViewsPanels {
@ -75,4 +80,5 @@ export default class JoplinViewsPanels {
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
isActive(handle: ViewHandle): Promise<boolean>;
}

View File

@ -1,17 +1,14 @@
import Plugin from '../Plugin';
export interface Implementation {
injectCustomStyles(elementId: string, cssFilePath: string): Promise<void>;
}
export default class JoplinWindow {
private plugin_;
private store_;
private implementation_;
constructor(implementation: Implementation, plugin: Plugin, store: any);
constructor(_plugin: Plugin, store: any);
/**
* Loads a chrome CSS file. It will apply to the window UI elements, except
* for the note viewer. It is the same as the "Custom stylesheet for
* Joplin-wide app styles" setting. See the [Load CSS Demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/load_css)
* for an example.
*
* <span class="platform-desktop">desktop</span>
*/
loadChromeCssFile(filePath: string): Promise<void>;
/**
@ -19,6 +16,8 @@ export default class JoplinWindow {
* exported or printed note. It is the same as the "Custom stylesheet for
* rendered Markdown" setting. See the [Load CSS Demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/load_css)
* for an example.
*
* <span class="platform-desktop">desktop</span>
*/
loadNoteCssFile(filePath: string): Promise<void>;
}

View File

@ -1,9 +1,6 @@
import Plugin from '../Plugin';
import { FolderEntity } from '../../database/types';
import { Disposable, MenuItem } from './types';
export interface EditContextMenuFilterObject {
items: MenuItem[];
}
type FilterHandler<T> = (object: T) => Promise<void>;
import { Disposable, EditContextMenuFilterObject, FilterHandler } from './types';
declare enum ItemChangeEventType {
Create = 1,
Update = 2,
@ -13,15 +10,25 @@ interface ItemChangeEvent {
id: string;
event: ItemChangeEventType;
}
interface SyncStartEvent {
withErrors: boolean;
}
interface ResourceChangeEvent {
id: string;
}
type ItemChangeHandler = (event: ItemChangeEvent) => void;
type SyncStartHandler = (event: SyncStartEvent) => void;
type ResourceChangeHandler = (event: ResourceChangeEvent) => void;
interface NoteContentChangeEvent {
note: any;
}
interface NoteSelectionChangeEvent {
value: string[];
}
interface NoteAlarmTriggerEvent {
noteId: string;
}
interface SyncCompleteEvent {
withErrors: boolean;
}
type WorkspaceEventHandler<EventType> = (event: EventType) => void;
type ItemChangeHandler = WorkspaceEventHandler<ItemChangeEvent>;
type SyncStartHandler = () => void;
type ResourceChangeHandler = WorkspaceEventHandler<ResourceChangeEvent>;
/**
* The workspace service provides access to all the parts of Joplin that
* are being worked on - i.e. the currently selected notes or notebooks as
@ -32,16 +39,17 @@ type ResourceChangeHandler = (event: ResourceChangeEvent) => void;
*/
export default class JoplinWorkspace {
private store;
constructor(store: any);
private plugin;
constructor(plugin: Plugin, store: any);
/**
* Called when a new note or notes are selected.
*/
onNoteSelectionChange(callback: Function): Promise<Disposable>;
onNoteSelectionChange(callback: WorkspaceEventHandler<NoteSelectionChangeEvent>): Promise<Disposable>;
/**
* Called when the content of a note changes.
* @deprecated Use `onNoteChange()` instead, which is reliably triggered whenever the note content, or any note property changes.
*/
onNoteContentChange(callback: Function): Promise<void>;
onNoteContentChange(callback: WorkspaceEventHandler<NoteContentChangeEvent>): Promise<void>;
/**
* Called when the content of the current note changes.
*/
@ -54,7 +62,7 @@ export default class JoplinWorkspace {
/**
* Called when an alarm associated with a to-do is triggered.
*/
onNoteAlarmTrigger(handler: Function): Promise<Disposable>;
onNoteAlarmTrigger(handler: WorkspaceEventHandler<NoteAlarmTriggerEvent>): Promise<Disposable>;
/**
* Called when the synchronisation process is starting.
*/
@ -62,14 +70,16 @@ export default class JoplinWorkspace {
/**
* Called when the synchronisation process has finished.
*/
onSyncComplete(callback: Function): Promise<Disposable>;
onSyncComplete(callback: WorkspaceEventHandler<SyncCompleteEvent>): Promise<Disposable>;
/**
* Called just before the editor context menu is about to open. Allows
* adding items to it.
*
* <span class="platform-desktop">desktop</span>
*/
filterEditorContextMenu(handler: FilterHandler<EditContextMenuFilterObject>): void;
/**
* Gets the currently selected note
* Gets the currently selected note. Will be `null` if no note is selected.
*/
selectedNote(): Promise<any>;
/**

View File

@ -1,5 +1,5 @@
import { Size } from './types';
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_data' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.deleted_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_data' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.deleted_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
export declare enum ItemFlow {
TopToBottom = "topToBottom",
LeftToRight = "leftToRight"
@ -10,29 +10,30 @@ export interface OnChangeEvent {
value: any;
noteId: string;
}
export interface OnClickEvent {
elementId: string;
}
export type OnRenderNoteHandler = (props: any) => Promise<RenderNoteView>;
export type OnChangeHandler = (event: OnChangeEvent) => Promise<void>;
export type OnClickHandler = (event: OnClickEvent) => Promise<void>;
/**
* Most of these are the built-in note properties, such as `note.title`,
* `note.todo_completed`, etc.
* Most of these are the built-in note properties, such as `note.title`, `note.todo_completed`, etc.
* complemented with special properties such as `note.isWatched`, to know if a note is currently
* opened in the external editor, and `note.tags` to get the list tags associated with the note.
*
* Additionally, the `item.*` properties are specific to the rendered item. The
* most important being `item.selected`, which you can use to display the
* selected note in a different way.
* The `note.todoStatusText` property is a localised description of the to-do status (e.g.
* "to-do, incomplete"). If you include an `<input type='checkbox' ... />` for to-do items that would
* otherwise be unlabelled, consider adding `note.todoStatusText` as the checkbox's `aria-label`.
*
* Finally some special properties are provided to make it easier to render
* notes. In particular, if possible prefer `note.titleHtml` to `note.title`
* since some important processing has already been done on the string, such as
* handling the search highlighter and escaping. Since it's HTML and already
* escaped you would insert it using `{{{titleHtml}}}` (triple-mustache syntax,
* which disables escaping).
* ## Item properties
*
* `notes.tag` gives you the list of tags associated with the note.
*
* `note.isWatched` tells you if the note is currently opened in an external
* editor. In which case you would generally display some indicator.
* The `item.*` properties are specific to the rendered item. The most important being
* `item.selected`, which you can use to display the selected note in a different way.
*/
export type ListRendererDepependency = ListRendererDatabaseDependency | 'item.size.width' | 'item.size.height' | 'item.selected' | 'note.titleHtml' | 'note.isWatched' | 'note.tags';
export type ListRendererDependency = ListRendererDatabaseDependency | 'item.index' | 'item.selected' | 'item.size.height' | 'item.size.width' | 'note.folder.title' | 'note.isWatched' | 'note.tags' | 'note.todoStatusText' | 'note.titleHtml';
export type ListRendererItemValueTemplates = Record<string, string>;
export declare const columnNames: readonly ["note.folder.title", "note.is_todo", "note.latitude", "note.longitude", "note.source_url", "note.tags", "note.title", "note.todo_completed", "note.todo_due", "note.user_created_time", "note.user_updated_time"];
export type ColumnName = typeof columnNames[number];
export interface ListRenderer {
/**
* It must be unique to your plugin.
@ -44,10 +45,15 @@ export interface ListRenderer {
* height.
*/
flow: ItemFlow;
/**
* Whether the renderer supports multiple columns. Applies only when `flow`
* is `topToBottom`. Defaults to `false`.
*/
multiColumns?: boolean;
/**
* The size of each item must be specified in advance for performance
* reasons, and cannot be changed afterwards. If the item flow is top to
* bottom, you only need to specificy the item height (the width will be
* bottom, you only need to specify the item height (the width will be
* ignored).
*/
itemSize: Size;
@ -74,20 +80,97 @@ export interface ListRenderer {
* that you do not add more than what you need since there is a performance
* penalty for each property.
*/
dependencies: ListRendererDepependency[];
dependencies?: ListRendererDependency[];
headerTemplate?: string;
headerHeight?: number;
onHeaderClick?: OnClickHandler;
/**
* This is the HTML template that will be used to render the note list item.
* This is a [Mustache template](https://github.com/janl/mustache.js) and it
* will receive the variable you return from `onRenderNote` as tags. For
* example, if you return a property named `formattedDate` from
* `onRenderNote`, you can insert it in the template using `Created date:
* {{formattedDate}}`.
* This property is set differently depending on the `multiColumns` property.
*
* In order to get syntax highlighting working here, it's recommended
* installing an editor extension such as [es6-string-html VSCode
* ## If `multiColumns` is `false`
*
* There is only one column and the template is used to render the entire row.
*
* This is the HTML template that will be used to render the note list item. This is a [Mustache
* template](https://github.com/janl/mustache.js) and it will receive the variable you return
* from `onRenderNote` as tags. For example, if you return a property named `formattedDate` from
* `onRenderNote`, you can insert it in the template using `Created date: {{formattedDate}}`
*
* ## If `multiColumns` is `true`
*
* Since there is multiple columns, this template will be used to render each note property
* within the row. For example if the current columns are the Updated and Title properties, this
* template will be called once to render the updated time and a second time to render the
* title. To display the current property, the generic `value` property is provided - it will be
* replaced at runtime by the actual note property. To render something different depending on
* the note property, use `itemValueTemplate`. A minimal example would be
* `<span>{{value}}</span>` which will simply render the current property inside a span tag.
*
* In order to get syntax highlighting working here, it's recommended installing an editor
* extension such as [es6-string-html VSCode
* extension](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
*
* ## Default property rendering
*
* Certain properties are automatically rendered once inserted in the Mustache template. Those
* are in particular all the date-related fields, such as `note.user_updated_time` or
* `note.todo_completed`. Internally, those are timestamps in milliseconds, however when
* rendered we display them as date/time strings using the user's preferred time format. Another
* notable auto-rendered property is `note.title` which is going to include additional HTML,
* such as the search markers.
*
* If you do not want this default rendering behaviour, for example if you want to display the
* raw timestamps in milliseconds, you can simply return custom properties from
* `onRenderNote()`. For example:
*
* ```typescript
* onRenderNote: async (props: any) => {
* return {
* ...props,
* // Return the property under a different name
* updatedTimeMs: props.note.user_updated_time,
* }
* },
*
* itemTemplate: // html
* `
* <div>
* Raw timestamp: {{updatedTimeMs}} <!-- This is **not** auto-rendered ->
* Formatted time: {{note.user_updated_time}} <!-- This is -->
* </div>
* `,
*
* ```
*
* See
* `[https://github.com/laurent22/joplin/blob/dev/packages/lib/services/noteList/renderViewProps.ts](renderViewProps.ts)`
* for the list of properties that have a default rendering.
*/
itemTemplate: string;
/**
* This property applies only when `multiColumns` is `true`. It is used to render something
* different for each note property.
*
* This is a map of actual dependencies to templates - you only need to return something if the
* default, as specified in `template`, is not enough.
*
* Again you need to return a Mustache template and it will be combined with the `template`
* property to create the final template. For example if you return a property named
* `formattedDate` from `onRenderNote`, you can insert it in the template using
* `{{formattedDate}}`. This string will replace `{{value}}` in the `template` property.
*
* So if the template property is set to `<span>{{value}}</span>`, the final template will be
* `<span>{{formattedDate}}</span>`.
*
* The property would be set as so:
*
* ```javascript
* itemValueTemplates: {
* 'note.user_updated_time': '{{formattedDate}}',
* }
* ```
*/
itemValueTemplates?: ListRendererItemValueTemplates;
/**
* This user-facing text is used for example in the View menu, so that your
* renderer can be selected.
@ -128,17 +211,15 @@ export interface ListRenderer {
*/
onRenderNote: OnRenderNoteHandler;
/**
* This handler allows adding some interacivity to the note renderer -
* whenever an input element within the item is changed (for example, when a
* checkbox is clicked, or a text input is changed), this `onChange` handler
* is going to be called.
* This handler allows adding some interactivity to the note renderer - whenever an input element
* within the item is changed (for example, when a checkbox is clicked, or a text input is
* changed), this `onChange` handler is going to be called.
*
* You can inspect `event.elementId` to know which element had some changes,
* and `event.value` to know the new value. `event.noteId` also tells you
* what note is affected, so that you can potentially apply changes to it.
* You can inspect `event.elementId` to know which element had some changes, and `event.value`
* to know the new value. `event.noteId` also tells you what note is affected, so that you can
* potentially apply changes to it.
*
* You specify the element ID, by setting a `data-id` attribute on the
* input.
* You specify the element ID, by setting a `data-id` attribute on the input.
*
* For example, if you have such a template:
*
@ -148,9 +229,26 @@ export interface ListRenderer {
* </div>
* ```
*
* The event handler will receive an event with `elementId` set to
* `noteTitleInput`.
* The event handler will receive an event with `elementId` set to `noteTitleInput`.
*
* ## Default event handlers
*
* Currently one click event is automatically handled:
*
* If there is a checkbox with a `data-id="todo-checkbox"` attribute is present, it is going to
* automatically toggle the note to-do "completed" status.
*
* For example this is what is used in the default list renderer:
*
* `<input data-id="todo-checkbox" type="checkbox" {{#note.todo_completed}}checked="checked"{{/note.todo_completed}}>`
*/
onChange?: OnChangeHandler;
}
export interface NoteListColumn {
name: ColumnName;
width: number;
}
export type NoteListColumns = NoteListColumn[];
export declare const defaultWidth = 100;
export declare const defaultListColumns: () => NoteListColumns;
export {};

View File

@ -3,7 +3,7 @@
import { Size } from './types';
// AUTO-GENERATED by generate-database-type
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_data' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.deleted_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_data' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.deleted_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
// AUTO-GENERATED by generate-database-type
export enum ItemFlow {
@ -11,45 +11,68 @@ export enum ItemFlow {
LeftToRight = 'leftToRight',
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export type RenderNoteView = Record<string, any>;
export interface OnChangeEvent {
elementId: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value: any;
noteId: string;
}
export interface OnClickEvent {
elementId: string;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export type OnRenderNoteHandler = (props: any)=> Promise<RenderNoteView>;
export type OnChangeHandler = (event: OnChangeEvent)=> Promise<void>;
export type OnClickHandler = (event: OnClickEvent)=> Promise<void>;
/**
* Most of these are the built-in note properties, such as `note.title`,
* `note.todo_completed`, etc.
* Most of these are the built-in note properties, such as `note.title`, `note.todo_completed`, etc.
* complemented with special properties such as `note.isWatched`, to know if a note is currently
* opened in the external editor, and `note.tags` to get the list tags associated with the note.
*
* Additionally, the `item.*` properties are specific to the rendered item. The
* most important being `item.selected`, which you can use to display the
* selected note in a different way.
* The `note.todoStatusText` property is a localised description of the to-do status (e.g.
* "to-do, incomplete"). If you include an `<input type='checkbox' ... />` for to-do items that would
* otherwise be unlabelled, consider adding `note.todoStatusText` as the checkbox's `aria-label`.
*
* Finally some special properties are provided to make it easier to render
* notes. In particular, if possible prefer `note.titleHtml` to `note.title`
* since some important processing has already been done on the string, such as
* handling the search highlighter and escaping. Since it's HTML and already
* escaped you would insert it using `{{{titleHtml}}}` (triple-mustache syntax,
* which disables escaping).
* ## Item properties
*
* `notes.tag` gives you the list of tags associated with the note.
*
* `note.isWatched` tells you if the note is currently opened in an external
* editor. In which case you would generally display some indicator.
* The `item.*` properties are specific to the rendered item. The most important being
* `item.selected`, which you can use to display the selected note in a different way.
*/
export type ListRendererDepependency =
export type ListRendererDependency =
ListRendererDatabaseDependency |
'item.size.width' |
'item.size.height' |
'item.index' |
'item.selected' |
'note.titleHtml' |
'item.size.height' |
'item.size.width' |
'note.folder.title' |
'note.isWatched' |
'note.tags';
'note.tags' |
'note.todoStatusText' |
'note.titleHtml';
export type ListRendererItemValueTemplates = Record<string, string>;
export const columnNames = [
'note.folder.title',
'note.is_todo',
'note.latitude',
'note.longitude',
'note.source_url',
'note.tags',
'note.title',
'note.todo_completed',
'note.todo_due',
'note.user_created_time',
'note.user_updated_time',
] as const;
export type ColumnName = typeof columnNames[number];
export interface ListRenderer {
/**
@ -64,10 +87,16 @@ export interface ListRenderer {
*/
flow: ItemFlow;
/**
* Whether the renderer supports multiple columns. Applies only when `flow`
* is `topToBottom`. Defaults to `false`.
*/
multiColumns?: boolean;
/**
* The size of each item must be specified in advance for performance
* reasons, and cannot be changed afterwards. If the item flow is top to
* bottom, you only need to specificy the item height (the width will be
* bottom, you only need to specify the item height (the width will be
* ignored).
*/
itemSize: Size;
@ -96,22 +125,101 @@ export interface ListRenderer {
* that you do not add more than what you need since there is a performance
* penalty for each property.
*/
dependencies: ListRendererDepependency[];
dependencies?: ListRendererDependency[];
headerTemplate?: string;
headerHeight?: number;
onHeaderClick?: OnClickHandler;
/**
* This is the HTML template that will be used to render the note list item.
* This is a [Mustache template](https://github.com/janl/mustache.js) and it
* will receive the variable you return from `onRenderNote` as tags. For
* example, if you return a property named `formattedDate` from
* `onRenderNote`, you can insert it in the template using `Created date:
* {{formattedDate}}`.
* This property is set differently depending on the `multiColumns` property.
*
* In order to get syntax highlighting working here, it's recommended
* installing an editor extension such as [es6-string-html VSCode
* ## If `multiColumns` is `false`
*
* There is only one column and the template is used to render the entire row.
*
* This is the HTML template that will be used to render the note list item. This is a [Mustache
* template](https://github.com/janl/mustache.js) and it will receive the variable you return
* from `onRenderNote` as tags. For example, if you return a property named `formattedDate` from
* `onRenderNote`, you can insert it in the template using `Created date: {{formattedDate}}`
*
* ## If `multiColumns` is `true`
*
* Since there is multiple columns, this template will be used to render each note property
* within the row. For example if the current columns are the Updated and Title properties, this
* template will be called once to render the updated time and a second time to render the
* title. To display the current property, the generic `value` property is provided - it will be
* replaced at runtime by the actual note property. To render something different depending on
* the note property, use `itemValueTemplate`. A minimal example would be
* `<span>{{value}}</span>` which will simply render the current property inside a span tag.
*
* In order to get syntax highlighting working here, it's recommended installing an editor
* extension such as [es6-string-html VSCode
* extension](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
*
* ## Default property rendering
*
* Certain properties are automatically rendered once inserted in the Mustache template. Those
* are in particular all the date-related fields, such as `note.user_updated_time` or
* `note.todo_completed`. Internally, those are timestamps in milliseconds, however when
* rendered we display them as date/time strings using the user's preferred time format. Another
* notable auto-rendered property is `note.title` which is going to include additional HTML,
* such as the search markers.
*
* If you do not want this default rendering behaviour, for example if you want to display the
* raw timestamps in milliseconds, you can simply return custom properties from
* `onRenderNote()`. For example:
*
* ```typescript
* onRenderNote: async (props: any) => {
* return {
* ...props,
* // Return the property under a different name
* updatedTimeMs: props.note.user_updated_time,
* }
* },
*
* itemTemplate: // html
* `
* <div>
* Raw timestamp: {{updatedTimeMs}} <!-- This is **not** auto-rendered ->
* Formatted time: {{note.user_updated_time}} <!-- This is -->
* </div>
* `,
*
* ```
*
* See
* `[https://github.com/laurent22/joplin/blob/dev/packages/lib/services/noteList/renderViewProps.ts](renderViewProps.ts)`
* for the list of properties that have a default rendering.
*/
itemTemplate: string;
/**
* This property applies only when `multiColumns` is `true`. It is used to render something
* different for each note property.
*
* This is a map of actual dependencies to templates - you only need to return something if the
* default, as specified in `template`, is not enough.
*
* Again you need to return a Mustache template and it will be combined with the `template`
* property to create the final template. For example if you return a property named
* `formattedDate` from `onRenderNote`, you can insert it in the template using
* `{{formattedDate}}`. This string will replace `{{value}}` in the `template` property.
*
* So if the template property is set to `<span>{{value}}</span>`, the final template will be
* `<span>{{formattedDate}}</span>`.
*
* The property would be set as so:
*
* ```javascript
* itemValueTemplates: {
* 'note.user_updated_time': '{{formattedDate}}',
* }
* ```
*/
itemValueTemplates?: ListRendererItemValueTemplates;
/**
* This user-facing text is used for example in the View menu, so that your
* renderer can be selected.
@ -154,17 +262,15 @@ export interface ListRenderer {
onRenderNote: OnRenderNoteHandler;
/**
* This handler allows adding some interacivity to the note renderer -
* whenever an input element within the item is changed (for example, when a
* checkbox is clicked, or a text input is changed), this `onChange` handler
* is going to be called.
* This handler allows adding some interactivity to the note renderer - whenever an input element
* within the item is changed (for example, when a checkbox is clicked, or a text input is
* changed), this `onChange` handler is going to be called.
*
* You can inspect `event.elementId` to know which element had some changes,
* and `event.value` to know the new value. `event.noteId` also tells you
* what note is affected, so that you can potentially apply changes to it.
* You can inspect `event.elementId` to know which element had some changes, and `event.value`
* to know the new value. `event.noteId` also tells you what note is affected, so that you can
* potentially apply changes to it.
*
* You specify the element ID, by setting a `data-id` attribute on the
* input.
* You specify the element ID, by setting a `data-id` attribute on the input.
*
* For example, if you have such a template:
*
@ -174,8 +280,46 @@ export interface ListRenderer {
* </div>
* ```
*
* The event handler will receive an event with `elementId` set to
* `noteTitleInput`.
* The event handler will receive an event with `elementId` set to `noteTitleInput`.
*
* ## Default event handlers
*
* Currently one click event is automatically handled:
*
* If there is a checkbox with a `data-id="todo-checkbox"` attribute is present, it is going to
* automatically toggle the note to-do "completed" status.
*
* For example this is what is used in the default list renderer:
*
* `<input data-id="todo-checkbox" type="checkbox" {{#note.todo_completed}}checked="checked"{{/note.todo_completed}}>`
*/
onChange?: OnChangeHandler;
}
export interface NoteListColumn {
name: ColumnName;
width: number;
}
export type NoteListColumns = NoteListColumn[];
export const defaultWidth = 100;
export const defaultListColumns = () => {
const columns: NoteListColumns = [
{
name: 'note.is_todo',
width: 30,
},
{
name: 'note.user_updated_time',
width: defaultWidth,
},
{
name: 'note.title',
width: 0,
},
];
return columns;
};

View File

@ -26,6 +26,7 @@ export interface Command {
/**
* Code to be ran when the command is executed. It may return a result.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
execute(...args: any[]): Promise<any | void>;
/**
@ -115,11 +116,13 @@ export interface ExportModule {
/**
* Called when an item needs to be processed. An "item" can be any Joplin object, such as a note, a folder, a notebook, etc.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onProcessItem(context: ExportContext, itemType: number, item: any): Promise<void>;
/**
* Called when a resource file needs to be exported.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onProcessResource(context: ExportContext, resource: any, filePath: string): Promise<void>;
/**
@ -181,13 +184,15 @@ export interface ExportContext {
options: ExportOptions;
/**
* You can attach your own custom data using this propery - it will then be passed to each event handler, allowing you to keep state from one event to the next.
* You can attach your own custom data using this property - it will then be passed to each event handler, allowing you to keep state from one event to the next.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
userData?: any;
}
export interface ImportContext {
sourcePath: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
options: any;
warnings: string[];
}
@ -197,6 +202,7 @@ export interface ImportContext {
// =================================================================
export interface Script {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onStart?(event: any): Promise<void>;
}
@ -227,6 +233,8 @@ export interface VersionInfo {
version: string;
profileVersion: number;
syncVersion: number;
platform: 'desktop'|'mobile';
}
// =================================================================
@ -300,6 +308,7 @@ export interface MenuItem {
* Arguments that should be passed to the command. They will be as rest
* parameters.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
commandArgs?: any[];
/**
@ -338,6 +347,8 @@ export type ButtonId = string;
export enum ToolbarButtonLocation {
/**
* This toolbar in the top right corner of the application. It applies to the note as a whole, including its metadata.
*
* <span class="platform-desktop">desktop</span>
*/
NoteToolbar = 'noteToolbar',
@ -351,11 +362,13 @@ export type ViewHandle = string;
export interface EditorCommand {
name: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value?: any;
}
export interface DialogResult {
id: ButtonId;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
formData?: any;
}
@ -371,6 +384,26 @@ export interface Rectangle {
height?: number;
}
export type ActivationCheckCallback = ()=> Promise<boolean>;
export type UpdateCallback = ()=> Promise<void>;
export type VisibleHandler = ()=> Promise<void>;
export interface EditContextMenuFilterObject {
items: MenuItem[];
}
export interface EditorActivationCheckFilterObject {
activatedEditors: {
pluginId: string;
viewId: string;
isActive: boolean;
}[];
}
export type FilterHandler<T> = (object: T)=> Promise<T>;
// =================================================================
// Settings types
// =================================================================
@ -404,6 +437,7 @@ export enum SettingStorage {
// Redefine a simplified interface to mask internal details
// and to remove function calls as they would have to be async.
export interface SettingItem {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value: any;
type: SettingItemType;
@ -440,6 +474,7 @@ export interface SettingItem {
* This property is required when `isEnum` is `true`. In which case, it
* should contain a map of value => label.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
options?: Record<any, any>;
/**
@ -497,6 +532,7 @@ export type Path = string[];
// Content Script types
// =================================================================
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export type PostMessageHandler = (message: any)=> Promise<any>;
/**
@ -520,30 +556,38 @@ export interface ContentScriptContext {
}
export interface ContentScriptModuleLoadedEvent {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
userData?: any;
}
export interface ContentScriptModule {
onLoaded?: (event: ContentScriptModuleLoadedEvent)=> void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
plugin: ()=> any;
assets?: ()=> void;
}
export interface MarkdownItContentScriptModule extends Omit<ContentScriptModule, 'plugin'> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
plugin: (markdownIt: any, options: any)=> any;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
type EditorCommandCallback = (...args: any[])=> any;
export interface CodeMirrorControl {
/** Points to a CodeMirror 6 EditorView instance. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
editor: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
cm6: any;
/** `extension` should be a [CodeMirror 6 extension](https://codemirror.net/docs/ref/#state.Extension). */
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
addExtension(extension: any|any[]): void;
supportsCommand(name: string): boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
execCommand(name: string, ...args: any[]): any;
registerCommand(name: string, callback: EditorCommandCallback): void;
@ -553,15 +597,17 @@ export interface CodeMirrorControl {
* registers the given [CompletionSource](https://codemirror.net/docs/ref/#autocomplete.CompletionSource).
*
* Use this extension rather than the built-in CodeMirror [`autocompletion`](https://codemirror.net/docs/ref/#autocomplete.autocompletion)
* if you don't want to use [langaugeData-based autocompletion](https://codemirror.net/docs/ref/#autocomplete.autocompletion^config.override).
* if you don't want to use [languageData-based autocompletion](https://codemirror.net/docs/ref/#autocomplete.autocompletion^config.override).
*
* Using `autocompletion({ override: [ ... ]})` causes errors when done by multiple plugins.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
completionSource(completionSource: any): any;
/**
* Creates an extension that enables or disables [`languageData`-based autocompletion](https://codemirror.net/docs/ref/#autocomplete.autocompletion^config.override).
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
enableLanguageDataAutocomplete: { of: (enabled: boolean)=> any };
};
}
@ -610,6 +656,45 @@ export enum ContentScriptType {
* plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts)
* to see how the data should be structured.
*
* ## Supporting the Rich Text Editor
*
* Joplin's Rich Text Editor works with rendered HTML, which is converted back
* to markdown when saving. To prevent the original markdown for your plugin from
* being lost, Joplin needs additional metadata.
*
* To provide this,
* 1. Wrap the HTML generated by your plugin in an element with class `joplin-editable`.
* For example,
* ```html
* <div class="joplin-editable">
* ...your html...
* </div>
* ```
* 2. Add a child with class `joplin-source` that contains the original markdown that
* was rendered by your plugin. Include `data-joplin-source-open`, `data-joplin-source-close`,
* and `data-joplin-language` attributes.
* For example, if your plugin rendered the following code block,
* ````
* ```foo
* ... original source here ...
* ```
* ````
* then it should render to
* ```html
* <div class="joplin-editable">
* <pre
* class="joplin-source"
* data-joplin-language="foo"
* data-joplin-source-open="```foo&NewLine;"
* data-joplin-source-close="```"
* > ... original source here ... </pre>
* ... rendered HTML here ...
* </div>
* ```
*
* See [the demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* for a complete example.
*
* ## Getting the settings from the renderer
*
* You can access your plugin settings from the renderer by calling
@ -684,21 +769,21 @@ export enum ContentScriptType {
* }
* ```
*
* - The `context` argument is currently unused but could be used later on
* to provide access to your own plugin so that the content script and
* plugin can communicate.
* - The `context` argument allows communicating with other parts of
* your plugin (see below).
*
* - The `plugin` key is your CodeMirror plugin. This is where you can
* register new commands with CodeMirror or interact with the CodeMirror
* instance as needed.
*
* - The `codeMirrorResources` key is an array of CodeMirror resources that
* - **CodeMirror 5 only**: The `codeMirrorResources` key is an array of CodeMirror resources that
* will be loaded and attached to the CodeMirror module. These are made up
* of addons, keymaps, and modes. For example, for a plugin that want's to
* enable clojure highlighting in code blocks. `codeMirrorResources` would
* be set to `['mode/clojure/clojure']`.
* This field is ignored on mobile and when the desktop beta editor is enabled.
*
* - The `codeMirrorOptions` key contains all the
* - **CodeMirror 5 only**: The `codeMirrorOptions` key contains all the
* [CodeMirror](https://codemirror.net/doc/manual.html#config) options
* that will be set or changed by this plugin. New options can alse be
* declared via
@ -716,9 +801,11 @@ export enum ContentScriptType {
* must be provided for the plugin to be valid. Having multiple or all
* provided is also okay.
*
* See also the [demo
* plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* for an example of all these keys being used in one plugin.
* See also:
* - The [demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* for an example of all these keys being used in one plugin.
* - See [the editor plugin tutorial](https://joplinapp.org/help/api/tutorials/cm6_plugin)
* for how to develop a plugin for the mobile editor and the desktop beta markdown editor.
*
* ## Posting messages from the content script to your plugin
*

View File

@ -68,6 +68,8 @@ export default class Joplin {
* - [fs-extra](https://www.npmjs.com/package/fs-extra)
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/nativeModule)
*
* <span class="platform-desktop">desktop</span>
*/
require(_path: string): any;
versionInfo(): Promise<import("./types").VersionInfo>;

View File

@ -4,14 +4,20 @@ export default class JoplinClipboard {
constructor(electronClipboard: any, electronNativeImage: any);
readText(): Promise<string>;
writeText(text: string): Promise<void>;
/** <span class="platform-desktop">desktop</span> */
readHtml(): Promise<string>;
/** <span class="platform-desktop">desktop</span> */
writeHtml(html: string): Promise<void>;
/**
* Returns the image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
*
* <span class="platform-desktop">desktop</span>
*/
readImage(): Promise<string>;
/**
* Takes an image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
*
* <span class="platform-desktop">desktop</span>
*/
writeImage(dataUrl: string): Promise<void>;
/**

View File

@ -1,4 +1,5 @@
import { Command } from './types';
import Plugin from '../Plugin';
/**
* This class allows executing or registering new Joplin commands. Commands
* can be executed or associated with
@ -20,6 +21,12 @@ import { Command } from './types';
* To view what arguments are supported, you can open any of these files
* and look at the `execute()` command.
*
* Note that many of these commands only work on desktop. The more limited list of mobile
* commands can be found in these places:
*
* * [Global commands](https://github.com/laurent22/joplin/tree/dev/packages/app-mobile/commands)
* * [Editor commands](https://github.com/laurent22/joplin/blob/dev/packages/app-mobile/components/NoteEditor/commandDeclarations.ts)
*
* ## Executing editor commands
*
* There might be a situation where you want to invoke editor commands
@ -49,9 +56,10 @@ import { Command } from './types';
*
*/
export default class JoplinCommands {
private plugin_;
constructor(plugin_: Plugin);
/**
* <span class="platform-desktop">desktop</span> Executes the given
* command.
* Executes the given command.
*
* The command can take any number of arguments, and the supported
* arguments will vary based on the command. For custom commands, this
@ -70,7 +78,7 @@ export default class JoplinCommands {
*/
execute(commandName: string, ...args: any[]): Promise<any | void>;
/**
* <span class="platform-desktop">desktop</span> Registers a new command.
* Registers a new command.
*
* ```typescript
* // Register a new commmand called "testCommand1"

View File

@ -21,7 +21,8 @@ export default class JoplinContentScripts {
* for more information.
*
* * [View the renderer demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* * [View the editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* * [View the editor plugin tutorial](https://joplinapp.org/help/api/tutorials/cm6_plugin)
* * [View the legacy editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
*
* See also the [postMessage demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*

View File

@ -2,7 +2,7 @@ import { ModelType } from '../../../BaseModel';
import Plugin from '../Plugin';
import { Path } from './types';
/**
* This module provides access to the Joplin data API: https://joplinapp.org/api/references/rest_api/
* This module provides access to the Joplin data API: https://joplinapp.org/help/api/references/rest_api
* This is the main way to retrieve data, such as notes, notebooks, tags, etc.
* or to update them or delete them.
*
@ -13,12 +13,12 @@ import { Path } from './types';
* In general you would use the methods in this class as if you were using a REST API. There are four methods that map to GET, POST, PUT and DELETE calls.
* And each method takes these parameters:
*
* * `path`: This is an array that represents the path to the resource in the form `["resouceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
* * `path`: This is an array that represents the path to the resource in the form `["resourceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
* * `query`: (Optional) The query parameters. In a URL, this is the part after the question mark "?". In this case, it should be an object with key/value pairs.
* * `data`: (Optional) Applies to PUT and POST calls only. The request body contains the data you want to create or modify, for example the content of a note or folder.
* * `files`: (Optional) Used to create new resources and associate them with files.
*
* Please refer to the [Joplin API documentation](https://joplinapp.org/api/references/rest_api/) for complete details about each call. As the plugin runs within the Joplin application **you do not need an authorisation token** to use this API.
* Please refer to the [Joplin API documentation](https://joplinapp.org/help/api/references/rest_api) for complete details about each call. As the plugin runs within the Joplin application **you do not need an authorisation token** to use this API.
*
* For example:
*

View File

@ -1,3 +1,4 @@
import { FilterHandler } from '../../../eventManager';
/**
* @ignore
*
@ -5,6 +6,6 @@
* so for now disable filters.
*/
export default class JoplinFilters {
on(name: string, callback: Function): Promise<void>;
off(name: string, callback: Function): Promise<void>;
on(name: string, callback: FilterHandler): Promise<void>;
off(name: string, callback: FilterHandler): Promise<void>;
}

View File

@ -1,12 +1,33 @@
import { Rectangle } from './types';
export interface Implementation {
nativeImage: any;
}
export interface CreateFromBufferOptions {
width?: number;
height?: number;
scaleFactor?: number;
}
export interface CreateFromPdfOptions {
/**
* The first page to export. Defaults to `1`, the first page in
* the document.
*/
minPage?: number;
/**
* The number of the last page to convert. Defaults to the last page
* if not given.
*
* If `maxPage` is greater than the number of pages in the PDF, all pages
* in the PDF will be converted to images.
*/
maxPage?: number;
scaleFactor?: number;
}
export interface PdfInfo {
pageCount: number;
}
export interface Implementation {
createFromPath: (path: string) => Promise<unknown>;
createFromPdf: (path: string, options: CreateFromPdfOptions) => Promise<unknown[]>;
getPdfInfo: (path: string) => Promise<PdfInfo>;
}
export interface ResizeOptions {
width?: number;
height?: number;
@ -24,6 +45,7 @@ export type Handle = string;
* [View the
* example](https://github.com/laurent22/joplin/blob/dev/packages/app-cli/tests/support/plugins/imaging/src/index.ts)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinImaging {
private implementation_;
@ -32,11 +54,20 @@ export default class JoplinImaging {
private createImageHandle;
private imageByHandle;
private cacheImage;
/**
* Creates an image from the provided path. Note that images and PDFs are supported. If you
* provide a URL instead of a local path, the file will be downloaded first then converted to an
* image.
*/
createFromPath(filePath: string): Promise<Handle>;
createFromResource(resourceId: string): Promise<Handle>;
createFromPdfPath(path: string, options?: CreateFromPdfOptions): Promise<Handle[]>;
createFromPdfResource(resourceId: string, options?: CreateFromPdfOptions): Promise<Handle[]>;
getPdfInfoFromPath(path: string): Promise<PdfInfo>;
getPdfInfoFromResource(resourceId: string): Promise<PdfInfo>;
getSize(handle: Handle): Promise<any>;
resize(handle: Handle, options?: ResizeOptions): Promise<string>;
crop(handle: Handle, rectange: Rectangle): Promise<string>;
crop(handle: Handle, rectangle: Rectangle): Promise<string>;
toPngFile(handle: Handle, filePath: string): Promise<void>;
/**
* Quality is between 0 and 100
@ -57,5 +88,5 @@ export default class JoplinImaging {
* Image data is not automatically deleted by Joplin so make sure you call
* this method on the handle once you are done.
*/
free(handle: Handle): Promise<void>;
free(handles: Handle[] | Handle): Promise<void>;
}

View File

@ -9,7 +9,10 @@ import { ExportModule, ImportModule } from './types';
*
* See the documentation of the [[ExportModule]] and [[ImportModule]] for more information.
*
* You may also want to refer to the Joplin API documentation to see the list of properties for each item (note, notebook, etc.) - https://joplinapp.org/api/references/rest_api/
* You may also want to refer to the Joplin API documentation to see the list of properties for each item (note, notebook, etc.) - https://joplinapp.org/help/api/references/rest_api
*
* <span class="platform-desktop">desktop</span>: While it is possible to register import and export
* modules on mobile, there is no GUI to activate them.
*/
export default class JoplinInterop {
registerExportModule(module: ExportModule): Promise<void>;

View File

@ -19,8 +19,6 @@ export type ChangeHandler = (event: ChangeEvent) => void;
export default class JoplinSettings {
private plugin_;
constructor(plugin: Plugin);
private get keyPrefix();
private namespacedKey;
/**
* Registers new settings.
* Note that registering a setting item is dynamic and will be gone next time Joplin starts.
@ -40,6 +38,12 @@ export default class JoplinSettings {
*/
registerSection(name: string, section: SettingSection): Promise<void>;
/**
* Gets setting values (only applies to setting you registered from your plugin)
*/
values(keys: string[] | string): Promise<Record<string, unknown>>;
/**
* @deprecated Use joplin.settings.values()
*
* Gets a setting value (only applies to setting you registered from your plugin)
*/
value(key: string): Promise<any>;

View File

@ -5,6 +5,7 @@ import JoplinViewsMenus from './JoplinViewsMenus';
import JoplinViewsToolbarButtons from './JoplinViewsToolbarButtons';
import JoplinViewsPanels from './JoplinViewsPanels';
import JoplinViewsNoteList from './JoplinViewsNoteList';
import JoplinViewsEditors from './JoplinViewsEditor';
/**
* This namespace provides access to view-related services.
*
@ -19,11 +20,13 @@ export default class JoplinViews {
private menus_;
private toolbarButtons_;
private dialogs_;
private editors_;
private noteList_;
private implementation_;
constructor(implementation: any, plugin: Plugin, store: any);
get dialogs(): JoplinViewsDialogs;
get panels(): JoplinViewsPanels;
get editors(): JoplinViewsEditors;
get menuItems(): JoplinViewsMenuItems;
get menus(): JoplinViewsMenus;
get toolbarButtons(): JoplinViewsToolbarButtons;

View File

@ -43,6 +43,14 @@ export default class JoplinViewsDialogs {
* Displays a message box with OK/Cancel buttons. Returns the button index that was clicked - "0" for OK and "1" for "Cancel"
*/
showMessageBox(message: string): Promise<number>;
/**
* Displays a dialog to select a file or a directory. Same options and
* output as
* https://www.electronjs.org/docs/latest/api/dialog#dialogshowopendialogbrowserwindow-options
*
* <span class="platform-desktop">desktop</span>
*/
showOpenDialog(options: any): Promise<any>;
/**
* Sets the dialog HTML content
*/
@ -56,7 +64,9 @@ export default class JoplinViewsDialogs {
*/
setButtons(handle: ViewHandle, buttons: ButtonSpec[]): Promise<ButtonSpec[]>;
/**
* Opens the dialog
* Opens the dialog.
*
* On desktop, this closes any copies of the dialog open in different windows.
*/
open(handle: ViewHandle): Promise<DialogResult>;
/**

View File

@ -0,0 +1,88 @@
import Plugin from '../Plugin';
import { ActivationCheckCallback, ViewHandle, UpdateCallback } from './types';
/**
* Allows creating alternative note editors. You can create a view to handle loading and saving the
* note, and do your own rendering.
*
* Although it may be used to implement an alternative text editor, the more common use case may be
* to render the note in a different, graphical way - for example displaying a graph, and
* saving/loading the graph data in the associated note. In that case, you would detect whether the
* current note contains graph data and, in this case, you'd display your viewer.
*
* Terminology: An editor is **active** when it can be used to edit the current note. Note that it
* doesn't necessarily mean that your editor is visible - it just means that the user has the option
* to switch to it (via the "toggle editor" button). A **visible** editor is active and is currently
* being displayed.
*
* To implement an editor you need to listen to two events:
*
* - `onActivationCheck`: This is a way for the app to know whether your editor should be active or
* not. Return `true` from this handler to activate your editor.
*
* - `onUpdate`: When this is called you should update your editor based on the current note
* content. Call `joplin.workspace.selectedNote()` to get the current note.
*
* - `showEditorPlugin` and `toggleEditorPlugin` commands. Additionally you can use these commands
* to display your editor via `joplin.commands.execute('showEditorPlugin')`. This is not always
* necessary since the user can switch to your editor using the "toggle editor" button, however
* you may want to programmatically display the editor in some cases - for example when creating a
* new note specific to your editor.
*
* Note that only one editor view can be active at a time. This is why it is important not to
* activate your view if it's not relevant to the current note. If more than one is active, it is
* undefined which editor is going to be used to display the note.
*
* For an example of editor plugin, see the [YesYouKan
* plugin](https://github.com/joplin/plugin-yesyoukan/blob/master/src/index.ts). In particular,
* check the logic around `onActivationCheck` and `onUpdate` since this is the entry points for
* using this API.
*/
export default class JoplinViewsEditors {
private store;
private plugin;
private activationCheckHandlers_;
constructor(plugin: Plugin, store: any);
private controller;
/**
* Creates a new editor view
*/
create(id: string): Promise<ViewHandle>;
/**
* Sets the editor HTML content
*/
setHtml(handle: ViewHandle, html: string): Promise<string>;
/**
* Adds and loads a new JS or CSS file into the panel.
*/
addScript(handle: ViewHandle, scriptPath: string): Promise<void>;
/**
* See [[JoplinViewPanels]]
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Emitted when the editor can potentially be activated - this for example when the current note
* is changed, or when the application is opened. At that point should can check the current
* note and decide whether your editor should be activated or not. If it should return `true`,
* otherwise return `false`.
*/
onActivationCheck(handle: ViewHandle, callback: ActivationCheckCallback): Promise<void>;
/**
* Emitted when the editor content should be updated. This for example when the currently
* selected note changes, or when the user makes the editor visible.
*/
onUpdate(handle: ViewHandle, callback: UpdateCallback): Promise<void>;
/**
* See [[JoplinViewPanels]]
*/
postMessage(handle: ViewHandle, message: any): void;
/**
* Tells whether the editor is active or not.
*/
isActive(handle: ViewHandle): Promise<boolean>;
/**
* Tells whether the editor is effectively visible or not. If the editor is inactive, this will
* return `false`. If the editor is active and the user has switched to it, it will return
* `true`. Otherwise it will return `false`.
*/
isVisible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -4,6 +4,8 @@ import Plugin from '../Plugin';
* Allows creating and managing menu items.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/register_command)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsMenuItems {
private store;

View File

@ -4,6 +4,8 @@ import Plugin from '../Plugin';
* Allows creating menus.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/menu)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsMenus {
private store;

View File

@ -1,6 +1,39 @@
import { Store } from 'redux';
import Plugin from '../Plugin';
import { ListRenderer } from './noteListType';
/**
* This API allows you to customise how each note in the note list is rendered.
* The renderer you implement follows a unidirectional data flow.
*
* The app provides the required dependencies whenever a note is updated - you
* process these dependencies, and return some props, which are then passed to
* your template and rendered. See [[ListRenderer]] for a detailed description
* of each property of the renderer.
*
* ## Reference
*
* * [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/note_list_renderer)
*
* * [Default simple renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultListRenderer.ts)
*
* * [Default detailed renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultMultiColumnsRenderer.ts)
*
* ## Screenshots:
*
* ### Top to bottom with title, date and body
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/TopToBottom.png"/>
*
* ### Left to right with thumbnails
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/LeftToRight_Thumbnails.png"/>
*
* ### Top to bottom with editable title
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/TopToBottom_Editable.png"/>
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsNoteList {
private plugin_;
private store_;

View File

@ -1,12 +1,17 @@
import Plugin from '../Plugin';
import { ViewHandle } from './types';
/**
* Allows creating and managing view panels. View panels currently are
* displayed at the right of the sidebar and allows displaying any HTML
* content (within a webview) and update it in real-time. For example it
* Allows creating and managing view panels. View panels allow displaying any HTML
* content (within a webview) and updating it in real-time. For example it
* could be used to display a table of content for the active note, or
* display various metadata or graph.
*
* On desktop, view panels currently are displayed at the right of the sidebar, though can
* be moved with "View" > "Change application layout".
*
* On mobile, view panels are shown in a tabbed dialog that can be opened using a
* toolbar button.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/toc)
*/
export default class JoplinViewsPanels {
@ -75,4 +80,5 @@ export default class JoplinViewsPanels {
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
isActive(handle: ViewHandle): Promise<boolean>;
}

View File

@ -1,17 +1,14 @@
import Plugin from '../Plugin';
export interface Implementation {
injectCustomStyles(elementId: string, cssFilePath: string): Promise<void>;
}
export default class JoplinWindow {
private plugin_;
private store_;
private implementation_;
constructor(implementation: Implementation, plugin: Plugin, store: any);
constructor(_plugin: Plugin, store: any);
/**
* Loads a chrome CSS file. It will apply to the window UI elements, except
* for the note viewer. It is the same as the "Custom stylesheet for
* Joplin-wide app styles" setting. See the [Load CSS Demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/load_css)
* for an example.
*
* <span class="platform-desktop">desktop</span>
*/
loadChromeCssFile(filePath: string): Promise<void>;
/**
@ -19,6 +16,8 @@ export default class JoplinWindow {
* exported or printed note. It is the same as the "Custom stylesheet for
* rendered Markdown" setting. See the [Load CSS Demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/load_css)
* for an example.
*
* <span class="platform-desktop">desktop</span>
*/
loadNoteCssFile(filePath: string): Promise<void>;
}

View File

@ -1,9 +1,6 @@
import Plugin from '../Plugin';
import { FolderEntity } from '../../database/types';
import { Disposable, MenuItem } from './types';
export interface EditContextMenuFilterObject {
items: MenuItem[];
}
type FilterHandler<T> = (object: T) => Promise<void>;
import { Disposable, EditContextMenuFilterObject, FilterHandler } from './types';
declare enum ItemChangeEventType {
Create = 1,
Update = 2,
@ -13,15 +10,25 @@ interface ItemChangeEvent {
id: string;
event: ItemChangeEventType;
}
interface SyncStartEvent {
withErrors: boolean;
}
interface ResourceChangeEvent {
id: string;
}
type ItemChangeHandler = (event: ItemChangeEvent) => void;
type SyncStartHandler = (event: SyncStartEvent) => void;
type ResourceChangeHandler = (event: ResourceChangeEvent) => void;
interface NoteContentChangeEvent {
note: any;
}
interface NoteSelectionChangeEvent {
value: string[];
}
interface NoteAlarmTriggerEvent {
noteId: string;
}
interface SyncCompleteEvent {
withErrors: boolean;
}
type WorkspaceEventHandler<EventType> = (event: EventType) => void;
type ItemChangeHandler = WorkspaceEventHandler<ItemChangeEvent>;
type SyncStartHandler = () => void;
type ResourceChangeHandler = WorkspaceEventHandler<ResourceChangeEvent>;
/**
* The workspace service provides access to all the parts of Joplin that
* are being worked on - i.e. the currently selected notes or notebooks as
@ -32,16 +39,17 @@ type ResourceChangeHandler = (event: ResourceChangeEvent) => void;
*/
export default class JoplinWorkspace {
private store;
constructor(store: any);
private plugin;
constructor(plugin: Plugin, store: any);
/**
* Called when a new note or notes are selected.
*/
onNoteSelectionChange(callback: Function): Promise<Disposable>;
onNoteSelectionChange(callback: WorkspaceEventHandler<NoteSelectionChangeEvent>): Promise<Disposable>;
/**
* Called when the content of a note changes.
* @deprecated Use `onNoteChange()` instead, which is reliably triggered whenever the note content, or any note property changes.
*/
onNoteContentChange(callback: Function): Promise<void>;
onNoteContentChange(callback: WorkspaceEventHandler<NoteContentChangeEvent>): Promise<void>;
/**
* Called when the content of the current note changes.
*/
@ -54,7 +62,7 @@ export default class JoplinWorkspace {
/**
* Called when an alarm associated with a to-do is triggered.
*/
onNoteAlarmTrigger(handler: Function): Promise<Disposable>;
onNoteAlarmTrigger(handler: WorkspaceEventHandler<NoteAlarmTriggerEvent>): Promise<Disposable>;
/**
* Called when the synchronisation process is starting.
*/
@ -62,14 +70,16 @@ export default class JoplinWorkspace {
/**
* Called when the synchronisation process has finished.
*/
onSyncComplete(callback: Function): Promise<Disposable>;
onSyncComplete(callback: WorkspaceEventHandler<SyncCompleteEvent>): Promise<Disposable>;
/**
* Called just before the editor context menu is about to open. Allows
* adding items to it.
*
* <span class="platform-desktop">desktop</span>
*/
filterEditorContextMenu(handler: FilterHandler<EditContextMenuFilterObject>): void;
/**
* Gets the currently selected note
* Gets the currently selected note. Will be `null` if no note is selected.
*/
selectedNote(): Promise<any>;
/**

View File

@ -1,5 +1,5 @@
import { Size } from './types';
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.deleted_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_data' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.deleted_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
export declare enum ItemFlow {
TopToBottom = "topToBottom",
LeftToRight = "leftToRight"
@ -10,18 +10,245 @@ export interface OnChangeEvent {
value: any;
noteId: string;
}
export interface OnClickEvent {
elementId: string;
}
export type OnRenderNoteHandler = (props: any) => Promise<RenderNoteView>;
export type OnChangeHandler = (event: OnChangeEvent) => Promise<void>;
export type ListRendererDepependency = ListRendererDatabaseDependency | 'item.size.width' | 'item.size.height' | 'item.selected' | 'note.titleHtml' | 'note.isWatched' | 'note.tags';
export type OnClickHandler = (event: OnClickEvent) => Promise<void>;
/**
* Most of these are the built-in note properties, such as `note.title`, `note.todo_completed`, etc.
* complemented with special properties such as `note.isWatched`, to know if a note is currently
* opened in the external editor, and `note.tags` to get the list tags associated with the note.
*
* The `note.todoStatusText` property is a localised description of the to-do status (e.g.
* "to-do, incomplete"). If you include an `<input type='checkbox' ... />` for to-do items that would
* otherwise be unlabelled, consider adding `note.todoStatusText` as the checkbox's `aria-label`.
*
* ## Item properties
*
* The `item.*` properties are specific to the rendered item. The most important being
* `item.selected`, which you can use to display the selected note in a different way.
*/
export type ListRendererDependency = ListRendererDatabaseDependency | 'item.index' | 'item.selected' | 'item.size.height' | 'item.size.width' | 'note.folder.title' | 'note.isWatched' | 'note.tags' | 'note.todoStatusText' | 'note.titleHtml';
export type ListRendererItemValueTemplates = Record<string, string>;
export declare const columnNames: readonly ["note.folder.title", "note.is_todo", "note.latitude", "note.longitude", "note.source_url", "note.tags", "note.title", "note.todo_completed", "note.todo_due", "note.user_created_time", "note.user_updated_time"];
export type ColumnName = typeof columnNames[number];
export interface ListRenderer {
/**
* It must be unique to your plugin.
*/
id: string;
/**
* Can be top to bottom or left to right. Left to right gives you more
* option to set the size of the items since you set both its width and
* height.
*/
flow: ItemFlow;
/**
* Whether the renderer supports multiple columns. Applies only when `flow`
* is `topToBottom`. Defaults to `false`.
*/
multiColumns?: boolean;
/**
* The size of each item must be specified in advance for performance
* reasons, and cannot be changed afterwards. If the item flow is top to
* bottom, you only need to specify the item height (the width will be
* ignored).
*/
itemSize: Size;
/**
* The CSS is relative to the list item container. What will appear in the
* page is essentially `.note-list-item { YOUR_CSS; }`. It means you can use
* child combinator with guarantee it will only apply to your own items. In
* this example, the styling will apply to `.note-list-item > .content`:
*
* ```css
* > .content {
* padding: 10px;
* }
* ```
*
* In order to get syntax highlighting working here, it's recommended
* installing an editor extension such as [es6-string-html VSCode
* extension](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
*/
itemCss?: string;
dependencies: ListRendererDepependency[];
/**
* List the dependencies that your plugin needs to render the note list
* items. Only these will be passed to your `onRenderNote` handler. Ensure
* that you do not add more than what you need since there is a performance
* penalty for each property.
*/
dependencies?: ListRendererDependency[];
headerTemplate?: string;
headerHeight?: number;
onHeaderClick?: OnClickHandler;
/**
* This property is set differently depending on the `multiColumns` property.
*
* ## If `multiColumns` is `false`
*
* There is only one column and the template is used to render the entire row.
*
* This is the HTML template that will be used to render the note list item. This is a [Mustache
* template](https://github.com/janl/mustache.js) and it will receive the variable you return
* from `onRenderNote` as tags. For example, if you return a property named `formattedDate` from
* `onRenderNote`, you can insert it in the template using `Created date: {{formattedDate}}`
*
* ## If `multiColumns` is `true`
*
* Since there is multiple columns, this template will be used to render each note property
* within the row. For example if the current columns are the Updated and Title properties, this
* template will be called once to render the updated time and a second time to render the
* title. To display the current property, the generic `value` property is provided - it will be
* replaced at runtime by the actual note property. To render something different depending on
* the note property, use `itemValueTemplate`. A minimal example would be
* `<span>{{value}}</span>` which will simply render the current property inside a span tag.
*
* In order to get syntax highlighting working here, it's recommended installing an editor
* extension such as [es6-string-html VSCode
* extension](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
*
* ## Default property rendering
*
* Certain properties are automatically rendered once inserted in the Mustache template. Those
* are in particular all the date-related fields, such as `note.user_updated_time` or
* `note.todo_completed`. Internally, those are timestamps in milliseconds, however when
* rendered we display them as date/time strings using the user's preferred time format. Another
* notable auto-rendered property is `note.title` which is going to include additional HTML,
* such as the search markers.
*
* If you do not want this default rendering behaviour, for example if you want to display the
* raw timestamps in milliseconds, you can simply return custom properties from
* `onRenderNote()`. For example:
*
* ```typescript
* onRenderNote: async (props: any) => {
* return {
* ...props,
* // Return the property under a different name
* updatedTimeMs: props.note.user_updated_time,
* }
* },
*
* itemTemplate: // html
* `
* <div>
* Raw timestamp: {{updatedTimeMs}} <!-- This is **not** auto-rendered ->
* Formatted time: {{note.user_updated_time}} <!-- This is -->
* </div>
* `,
*
* ```
*
* See
* `[https://github.com/laurent22/joplin/blob/dev/packages/lib/services/noteList/renderViewProps.ts](renderViewProps.ts)`
* for the list of properties that have a default rendering.
*/
itemTemplate: string;
/**
* This property applies only when `multiColumns` is `true`. It is used to render something
* different for each note property.
*
* This is a map of actual dependencies to templates - you only need to return something if the
* default, as specified in `template`, is not enough.
*
* Again you need to return a Mustache template and it will be combined with the `template`
* property to create the final template. For example if you return a property named
* `formattedDate` from `onRenderNote`, you can insert it in the template using
* `{{formattedDate}}`. This string will replace `{{value}}` in the `template` property.
*
* So if the template property is set to `<span>{{value}}</span>`, the final template will be
* `<span>{{formattedDate}}</span>`.
*
* The property would be set as so:
*
* ```javascript
* itemValueTemplates: {
* 'note.user_updated_time': '{{formattedDate}}',
* }
* ```
*/
itemValueTemplates?: ListRendererItemValueTemplates;
/**
* This user-facing text is used for example in the View menu, so that your
* renderer can be selected.
*/
label: () => Promise<string>;
/**
* This is where most of the real-time processing will happen. When a note
* is rendered for the first time and every time it changes, this handler
* receives the properties specified in the `dependencies` property. You can
* then process them, load any additional data you need, and once done you
* need to return the properties that are needed in the `itemTemplate` HTML.
* Again, to use the formatted date example, you could have such a renderer:
*
* ```typescript
* dependencies: [
* 'note.title',
* 'note.created_time',
* ],
*
* itemTemplate: // html
* `
* <div>
* Title: {{note.title}}<br/>
* Date: {{formattedDate}}
* </div>
* `,
*
* onRenderNote: async (props: any) => {
* const formattedDate = dayjs(props.note.created_time).format();
* return {
* // Also return the props, so that note.title is available from the
* // template
* ...props,
* formattedDate,
* }
* },
* ```
*/
onRenderNote: OnRenderNoteHandler;
/**
* This handler allows adding some interactivity to the note renderer - whenever an input element
* within the item is changed (for example, when a checkbox is clicked, or a text input is
* changed), this `onChange` handler is going to be called.
*
* You can inspect `event.elementId` to know which element had some changes, and `event.value`
* to know the new value. `event.noteId` also tells you what note is affected, so that you can
* potentially apply changes to it.
*
* You specify the element ID, by setting a `data-id` attribute on the input.
*
* For example, if you have such a template:
*
* ```html
* <div>
* <input type="text" value="{{note.title}}" data-id="noteTitleInput"/>
* </div>
* ```
*
* The event handler will receive an event with `elementId` set to `noteTitleInput`.
*
* ## Default event handlers
*
* Currently one click event is automatically handled:
*
* If there is a checkbox with a `data-id="todo-checkbox"` attribute is present, it is going to
* automatically toggle the note to-do "completed" status.
*
* For example this is what is used in the default list renderer:
*
* `<input data-id="todo-checkbox" type="checkbox" {{#note.todo_completed}}checked="checked"{{/note.todo_completed}}>`
*/
onChange?: OnChangeHandler;
}
export interface NoteListColumn {
name: ColumnName;
width: number;
}
export type NoteListColumns = NoteListColumn[];
export declare const defaultWidth = 100;
export declare const defaultListColumns: () => NoteListColumns;
export {};

View File

@ -1,7 +1,9 @@
/* eslint-disable multiline-comment-style */
import { Size } from './types';
// AUTO-GENERATED by generate-database-type
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
type ListRendererDatabaseDependency = 'folder.created_time' | 'folder.deleted_time' | 'folder.encryption_applied' | 'folder.encryption_cipher_text' | 'folder.icon' | 'folder.id' | 'folder.is_shared' | 'folder.master_key_id' | 'folder.parent_id' | 'folder.share_id' | 'folder.title' | 'folder.updated_time' | 'folder.user_created_time' | 'folder.user_data' | 'folder.user_updated_time' | 'folder.type_' | 'note.altitude' | 'note.application_data' | 'note.author' | 'note.body' | 'note.conflict_original_id' | 'note.created_time' | 'note.deleted_time' | 'note.encryption_applied' | 'note.encryption_cipher_text' | 'note.id' | 'note.is_conflict' | 'note.is_shared' | 'note.is_todo' | 'note.latitude' | 'note.longitude' | 'note.markup_language' | 'note.master_key_id' | 'note.order' | 'note.parent_id' | 'note.share_id' | 'note.source' | 'note.source_application' | 'note.source_url' | 'note.title' | 'note.todo_completed' | 'note.todo_due' | 'note.updated_time' | 'note.user_created_time' | 'note.user_data' | 'note.user_updated_time' | 'note.type_';
// AUTO-GENERATED by generate-database-type
export enum ItemFlow {
@ -9,34 +11,315 @@ export enum ItemFlow {
LeftToRight = 'leftToRight',
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export type RenderNoteView = Record<string, any>;
export interface OnChangeEvent {
elementId: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value: any;
noteId: string;
}
export interface OnClickEvent {
elementId: string;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export type OnRenderNoteHandler = (props: any)=> Promise<RenderNoteView>;
export type OnChangeHandler = (event: OnChangeEvent)=> Promise<void>;
export type OnClickHandler = (event: OnClickEvent)=> Promise<void>;
export type ListRendererDepependency =
/**
* Most of these are the built-in note properties, such as `note.title`, `note.todo_completed`, etc.
* complemented with special properties such as `note.isWatched`, to know if a note is currently
* opened in the external editor, and `note.tags` to get the list tags associated with the note.
*
* The `note.todoStatusText` property is a localised description of the to-do status (e.g.
* "to-do, incomplete"). If you include an `<input type='checkbox' ... />` for to-do items that would
* otherwise be unlabelled, consider adding `note.todoStatusText` as the checkbox's `aria-label`.
*
* ## Item properties
*
* The `item.*` properties are specific to the rendered item. The most important being
* `item.selected`, which you can use to display the selected note in a different way.
*/
export type ListRendererDependency =
ListRendererDatabaseDependency |
'item.size.width' |
'item.size.height' |
'item.index' |
'item.selected' |
'note.titleHtml' |
'item.size.height' |
'item.size.width' |
'note.folder.title' |
'note.isWatched' |
'note.tags';
'note.tags' |
'note.todoStatusText' |
'note.titleHtml';
export type ListRendererItemValueTemplates = Record<string, string>;
export const columnNames = [
'note.folder.title',
'note.is_todo',
'note.latitude',
'note.longitude',
'note.source_url',
'note.tags',
'note.title',
'note.todo_completed',
'note.todo_due',
'note.user_created_time',
'note.user_updated_time',
] as const;
export type ColumnName = typeof columnNames[number];
export interface ListRenderer {
/**
* It must be unique to your plugin.
*/
id: string;
/**
* Can be top to bottom or left to right. Left to right gives you more
* option to set the size of the items since you set both its width and
* height.
*/
flow: ItemFlow;
/**
* Whether the renderer supports multiple columns. Applies only when `flow`
* is `topToBottom`. Defaults to `false`.
*/
multiColumns?: boolean;
/**
* The size of each item must be specified in advance for performance
* reasons, and cannot be changed afterwards. If the item flow is top to
* bottom, you only need to specify the item height (the width will be
* ignored).
*/
itemSize: Size;
/**
* The CSS is relative to the list item container. What will appear in the
* page is essentially `.note-list-item { YOUR_CSS; }`. It means you can use
* child combinator with guarantee it will only apply to your own items. In
* this example, the styling will apply to `.note-list-item > .content`:
*
* ```css
* > .content {
* padding: 10px;
* }
* ```
*
* In order to get syntax highlighting working here, it's recommended
* installing an editor extension such as [es6-string-html VSCode
* extension](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
*/
itemCss?: string;
dependencies: ListRendererDepependency[];
/**
* List the dependencies that your plugin needs to render the note list
* items. Only these will be passed to your `onRenderNote` handler. Ensure
* that you do not add more than what you need since there is a performance
* penalty for each property.
*/
dependencies?: ListRendererDependency[];
headerTemplate?: string;
headerHeight?: number;
onHeaderClick?: OnClickHandler;
/**
* This property is set differently depending on the `multiColumns` property.
*
* ## If `multiColumns` is `false`
*
* There is only one column and the template is used to render the entire row.
*
* This is the HTML template that will be used to render the note list item. This is a [Mustache
* template](https://github.com/janl/mustache.js) and it will receive the variable you return
* from `onRenderNote` as tags. For example, if you return a property named `formattedDate` from
* `onRenderNote`, you can insert it in the template using `Created date: {{formattedDate}}`
*
* ## If `multiColumns` is `true`
*
* Since there is multiple columns, this template will be used to render each note property
* within the row. For example if the current columns are the Updated and Title properties, this
* template will be called once to render the updated time and a second time to render the
* title. To display the current property, the generic `value` property is provided - it will be
* replaced at runtime by the actual note property. To render something different depending on
* the note property, use `itemValueTemplate`. A minimal example would be
* `<span>{{value}}</span>` which will simply render the current property inside a span tag.
*
* In order to get syntax highlighting working here, it's recommended installing an editor
* extension such as [es6-string-html VSCode
* extension](https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html)
*
* ## Default property rendering
*
* Certain properties are automatically rendered once inserted in the Mustache template. Those
* are in particular all the date-related fields, such as `note.user_updated_time` or
* `note.todo_completed`. Internally, those are timestamps in milliseconds, however when
* rendered we display them as date/time strings using the user's preferred time format. Another
* notable auto-rendered property is `note.title` which is going to include additional HTML,
* such as the search markers.
*
* If you do not want this default rendering behaviour, for example if you want to display the
* raw timestamps in milliseconds, you can simply return custom properties from
* `onRenderNote()`. For example:
*
* ```typescript
* onRenderNote: async (props: any) => {
* return {
* ...props,
* // Return the property under a different name
* updatedTimeMs: props.note.user_updated_time,
* }
* },
*
* itemTemplate: // html
* `
* <div>
* Raw timestamp: {{updatedTimeMs}} <!-- This is **not** auto-rendered ->
* Formatted time: {{note.user_updated_time}} <!-- This is -->
* </div>
* `,
*
* ```
*
* See
* `[https://github.com/laurent22/joplin/blob/dev/packages/lib/services/noteList/renderViewProps.ts](renderViewProps.ts)`
* for the list of properties that have a default rendering.
*/
itemTemplate: string;
/**
* This property applies only when `multiColumns` is `true`. It is used to render something
* different for each note property.
*
* This is a map of actual dependencies to templates - you only need to return something if the
* default, as specified in `template`, is not enough.
*
* Again you need to return a Mustache template and it will be combined with the `template`
* property to create the final template. For example if you return a property named
* `formattedDate` from `onRenderNote`, you can insert it in the template using
* `{{formattedDate}}`. This string will replace `{{value}}` in the `template` property.
*
* So if the template property is set to `<span>{{value}}</span>`, the final template will be
* `<span>{{formattedDate}}</span>`.
*
* The property would be set as so:
*
* ```javascript
* itemValueTemplates: {
* 'note.user_updated_time': '{{formattedDate}}',
* }
* ```
*/
itemValueTemplates?: ListRendererItemValueTemplates;
/**
* This user-facing text is used for example in the View menu, so that your
* renderer can be selected.
*/
label: ()=> Promise<string>;
/**
* This is where most of the real-time processing will happen. When a note
* is rendered for the first time and every time it changes, this handler
* receives the properties specified in the `dependencies` property. You can
* then process them, load any additional data you need, and once done you
* need to return the properties that are needed in the `itemTemplate` HTML.
* Again, to use the formatted date example, you could have such a renderer:
*
* ```typescript
* dependencies: [
* 'note.title',
* 'note.created_time',
* ],
*
* itemTemplate: // html
* `
* <div>
* Title: {{note.title}}<br/>
* Date: {{formattedDate}}
* </div>
* `,
*
* onRenderNote: async (props: any) => {
* const formattedDate = dayjs(props.note.created_time).format();
* return {
* // Also return the props, so that note.title is available from the
* // template
* ...props,
* formattedDate,
* }
* },
* ```
*/
onRenderNote: OnRenderNoteHandler;
/**
* This handler allows adding some interactivity to the note renderer - whenever an input element
* within the item is changed (for example, when a checkbox is clicked, or a text input is
* changed), this `onChange` handler is going to be called.
*
* You can inspect `event.elementId` to know which element had some changes, and `event.value`
* to know the new value. `event.noteId` also tells you what note is affected, so that you can
* potentially apply changes to it.
*
* You specify the element ID, by setting a `data-id` attribute on the input.
*
* For example, if you have such a template:
*
* ```html
* <div>
* <input type="text" value="{{note.title}}" data-id="noteTitleInput"/>
* </div>
* ```
*
* The event handler will receive an event with `elementId` set to `noteTitleInput`.
*
* ## Default event handlers
*
* Currently one click event is automatically handled:
*
* If there is a checkbox with a `data-id="todo-checkbox"` attribute is present, it is going to
* automatically toggle the note to-do "completed" status.
*
* For example this is what is used in the default list renderer:
*
* `<input data-id="todo-checkbox" type="checkbox" {{#note.todo_completed}}checked="checked"{{/note.todo_completed}}>`
*/
onChange?: OnChangeHandler;
}
export interface NoteListColumn {
name: ColumnName;
width: number;
}
export type NoteListColumns = NoteListColumn[];
export const defaultWidth = 100;
export const defaultListColumns = () => {
const columns: NoteListColumns = [
{
name: 'note.is_todo',
width: 30,
},
{
name: 'note.user_updated_time',
width: defaultWidth,
},
{
name: 'note.title',
width: 0,
},
];
return columns;
};

View File

@ -26,6 +26,7 @@ export interface Command {
/**
* Code to be ran when the command is executed. It may return a result.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
execute(...args: any[]): Promise<any | void>;
/**
@ -115,11 +116,13 @@ export interface ExportModule {
/**
* Called when an item needs to be processed. An "item" can be any Joplin object, such as a note, a folder, a notebook, etc.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onProcessItem(context: ExportContext, itemType: number, item: any): Promise<void>;
/**
* Called when a resource file needs to be exported.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onProcessResource(context: ExportContext, resource: any, filePath: string): Promise<void>;
/**
@ -181,13 +184,15 @@ export interface ExportContext {
options: ExportOptions;
/**
* You can attach your own custom data using this propery - it will then be passed to each event handler, allowing you to keep state from one event to the next.
* You can attach your own custom data using this property - it will then be passed to each event handler, allowing you to keep state from one event to the next.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
userData?: any;
}
export interface ImportContext {
sourcePath: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
options: any;
warnings: string[];
}
@ -197,6 +202,7 @@ export interface ImportContext {
// =================================================================
export interface Script {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
onStart?(event: any): Promise<void>;
}
@ -227,6 +233,8 @@ export interface VersionInfo {
version: string;
profileVersion: number;
syncVersion: number;
platform: 'desktop'|'mobile';
}
// =================================================================
@ -300,6 +308,7 @@ export interface MenuItem {
* Arguments that should be passed to the command. They will be as rest
* parameters.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
commandArgs?: any[];
/**
@ -338,6 +347,8 @@ export type ButtonId = string;
export enum ToolbarButtonLocation {
/**
* This toolbar in the top right corner of the application. It applies to the note as a whole, including its metadata.
*
* <span class="platform-desktop">desktop</span>
*/
NoteToolbar = 'noteToolbar',
@ -351,11 +362,13 @@ export type ViewHandle = string;
export interface EditorCommand {
name: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value?: any;
}
export interface DialogResult {
id: ButtonId;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
formData?: any;
}
@ -371,6 +384,26 @@ export interface Rectangle {
height?: number;
}
export type ActivationCheckCallback = ()=> Promise<boolean>;
export type UpdateCallback = ()=> Promise<void>;
export type VisibleHandler = ()=> Promise<void>;
export interface EditContextMenuFilterObject {
items: MenuItem[];
}
export interface EditorActivationCheckFilterObject {
activatedEditors: {
pluginId: string;
viewId: string;
isActive: boolean;
}[];
}
export type FilterHandler<T> = (object: T)=> Promise<T>;
// =================================================================
// Settings types
// =================================================================
@ -404,6 +437,7 @@ export enum SettingStorage {
// Redefine a simplified interface to mask internal details
// and to remove function calls as they would have to be async.
export interface SettingItem {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
value: any;
type: SettingItemType;
@ -440,6 +474,7 @@ export interface SettingItem {
* This property is required when `isEnum` is `true`. In which case, it
* should contain a map of value => label.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
options?: Record<any, any>;
/**
@ -497,6 +532,7 @@ export type Path = string[];
// Content Script types
// =================================================================
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
export type PostMessageHandler = (message: any)=> Promise<any>;
/**
@ -519,6 +555,67 @@ export interface ContentScriptContext {
postMessage: PostMessageHandler;
}
export interface ContentScriptModuleLoadedEvent {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
userData?: any;
}
export interface ContentScriptModule {
onLoaded?: (event: ContentScriptModuleLoadedEvent)=> void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
plugin: ()=> any;
assets?: ()=> void;
}
export interface MarkdownItContentScriptModule extends Omit<ContentScriptModule, 'plugin'> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
plugin: (markdownIt: any, options: any)=> any;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
type EditorCommandCallback = (...args: any[])=> any;
export interface CodeMirrorControl {
/** Points to a CodeMirror 6 EditorView instance. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
editor: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
cm6: any;
/** `extension` should be a [CodeMirror 6 extension](https://codemirror.net/docs/ref/#state.Extension). */
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
addExtension(extension: any|any[]): void;
supportsCommand(name: string): boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
execCommand(name: string, ...args: any[]): any;
registerCommand(name: string, callback: EditorCommandCallback): void;
joplinExtensions: {
/**
* Returns a [CodeMirror 6 extension](https://codemirror.net/docs/ref/#state.Extension) that
* registers the given [CompletionSource](https://codemirror.net/docs/ref/#autocomplete.CompletionSource).
*
* Use this extension rather than the built-in CodeMirror [`autocompletion`](https://codemirror.net/docs/ref/#autocomplete.autocompletion)
* if you don't want to use [languageData-based autocompletion](https://codemirror.net/docs/ref/#autocomplete.autocompletion^config.override).
*
* Using `autocompletion({ override: [ ... ]})` causes errors when done by multiple plugins.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
completionSource(completionSource: any): any;
/**
* Creates an extension that enables or disables [`languageData`-based autocompletion](https://codemirror.net/docs/ref/#autocomplete.autocompletion^config.override).
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
enableLanguageDataAutocomplete: { of: (enabled: boolean)=> any };
};
}
export interface MarkdownEditorContentScriptModule extends Omit<ContentScriptModule, 'plugin'> {
plugin: (editorControl: CodeMirrorControl)=> void;
}
export enum ContentScriptType {
/**
* Registers a new Markdown-It plugin, which should follow the template
@ -528,7 +625,7 @@ export enum ContentScriptType {
* module.exports = {
* default: function(context) {
* return {
* plugin: function(markdownIt, options) {
* plugin: function(markdownIt, pluginOptions) {
* // ...
* },
* assets: {
@ -538,6 +635,7 @@ export enum ContentScriptType {
* }
* }
* ```
*
* See [the
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* for a simple Markdown-it plugin example.
@ -550,10 +648,7 @@ export enum ContentScriptType {
*
* - The **required** `plugin` key is the actual Markdown-It plugin - check
* the [official doc](https://github.com/markdown-it/markdown-it) for more
* information. The `options` parameter is of type
* [RuleOptions](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml.ts),
* which contains a number of options, mostly useful for Joplin's internal
* code.
* information.
*
* - Using the **optional** `assets` key you may specify assets such as JS
* or CSS that should be loaded in the rendered HTML document. Check for
@ -561,6 +656,50 @@ export enum ContentScriptType {
* plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts)
* to see how the data should be structured.
*
* ## Supporting the Rich Text Editor
*
* Joplin's Rich Text Editor works with rendered HTML, which is converted back
* to markdown when saving. To prevent the original markdown for your plugin from
* being lost, Joplin needs additional metadata.
*
* To provide this,
* 1. Wrap the HTML generated by your plugin in an element with class `joplin-editable`.
* For example,
* ```html
* <div class="joplin-editable">
* ...your html...
* </div>
* ```
* 2. Add a child with class `joplin-source` that contains the original markdown that
* was rendered by your plugin. Include `data-joplin-source-open`, `data-joplin-source-close`,
* and `data-joplin-language` attributes.
* For example, if your plugin rendered the following code block,
* ````
* ```foo
* ... original source here ...
* ```
* ````
* then it should render to
* ```html
* <div class="joplin-editable">
* <pre
* class="joplin-source"
* data-joplin-language="foo"
* data-joplin-source-open="```foo&NewLine;"
* data-joplin-source-close="```"
* > ... original source here ... </pre>
* ... rendered HTML here ...
* </div>
* ```
*
* See [the demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* for a complete example.
*
* ## Getting the settings from the renderer
*
* You can access your plugin settings from the renderer by calling
* `pluginOptions.settingValue("your-setting-key')`.
*
* ## Posting messages from the content script to your plugin
*
* The application provides the following function to allow executing
@ -630,21 +769,21 @@ export enum ContentScriptType {
* }
* ```
*
* - The `context` argument is currently unused but could be used later on
* to provide access to your own plugin so that the content script and
* plugin can communicate.
* - The `context` argument allows communicating with other parts of
* your plugin (see below).
*
* - The `plugin` key is your CodeMirror plugin. This is where you can
* register new commands with CodeMirror or interact with the CodeMirror
* instance as needed.
*
* - The `codeMirrorResources` key is an array of CodeMirror resources that
* - **CodeMirror 5 only**: The `codeMirrorResources` key is an array of CodeMirror resources that
* will be loaded and attached to the CodeMirror module. These are made up
* of addons, keymaps, and modes. For example, for a plugin that want's to
* enable clojure highlighting in code blocks. `codeMirrorResources` would
* be set to `['mode/clojure/clojure']`.
* This field is ignored on mobile and when the desktop beta editor is enabled.
*
* - The `codeMirrorOptions` key contains all the
* - **CodeMirror 5 only**: The `codeMirrorOptions` key contains all the
* [CodeMirror](https://codemirror.net/doc/manual.html#config) options
* that will be set or changed by this plugin. New options can alse be
* declared via
@ -662,9 +801,11 @@ export enum ContentScriptType {
* must be provided for the plugin to be valid. Having multiple or all
* provided is also okay.
*
* See also the [demo
* plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* for an example of all these keys being used in one plugin.
* See also:
* - The [demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* for an example of all these keys being used in one plugin.
* - See [the editor plugin tutorial](https://joplinapp.org/help/api/tutorials/cm6_plugin)
* for how to develop a plugin for the mobile editor and the desktop beta markdown editor.
*
* ## Posting messages from the content script to your plugin
*

View File

@ -68,6 +68,8 @@ export default class Joplin {
* - [fs-extra](https://www.npmjs.com/package/fs-extra)
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/nativeModule)
*
* <span class="platform-desktop">desktop</span>
*/
require(_path: string): any;
versionInfo(): Promise<import("./types").VersionInfo>;

View File

@ -4,14 +4,20 @@ export default class JoplinClipboard {
constructor(electronClipboard: any, electronNativeImage: any);
readText(): Promise<string>;
writeText(text: string): Promise<void>;
/** <span class="platform-desktop">desktop</span> */
readHtml(): Promise<string>;
/** <span class="platform-desktop">desktop</span> */
writeHtml(html: string): Promise<void>;
/**
* Returns the image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
*
* <span class="platform-desktop">desktop</span>
*/
readImage(): Promise<string>;
/**
* Takes an image in [data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) format.
*
* <span class="platform-desktop">desktop</span>
*/
writeImage(dataUrl: string): Promise<void>;
/**

View File

@ -1,4 +1,5 @@
import { Command } from './types';
import Plugin from '../Plugin';
/**
* This class allows executing or registering new Joplin commands. Commands
* can be executed or associated with
@ -20,6 +21,12 @@ import { Command } from './types';
* To view what arguments are supported, you can open any of these files
* and look at the `execute()` command.
*
* Note that many of these commands only work on desktop. The more limited list of mobile
* commands can be found in these places:
*
* * [Global commands](https://github.com/laurent22/joplin/tree/dev/packages/app-mobile/commands)
* * [Editor commands](https://github.com/laurent22/joplin/blob/dev/packages/app-mobile/components/NoteEditor/commandDeclarations.ts)
*
* ## Executing editor commands
*
* There might be a situation where you want to invoke editor commands
@ -49,9 +56,10 @@ import { Command } from './types';
*
*/
export default class JoplinCommands {
private plugin_;
constructor(plugin_: Plugin);
/**
* <span class="platform-desktop">desktop</span> Executes the given
* command.
* Executes the given command.
*
* The command can take any number of arguments, and the supported
* arguments will vary based on the command. For custom commands, this
@ -70,7 +78,7 @@ export default class JoplinCommands {
*/
execute(commandName: string, ...args: any[]): Promise<any | void>;
/**
* <span class="platform-desktop">desktop</span> Registers a new command.
* Registers a new command.
*
* ```typescript
* // Register a new commmand called "testCommand1"

View File

@ -21,7 +21,8 @@ export default class JoplinContentScripts {
* for more information.
*
* * [View the renderer demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
* * [View the editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
* * [View the editor plugin tutorial](https://joplinapp.org/help/api/tutorials/cm6_plugin)
* * [View the legacy editor demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/codemirror_content_script)
*
* See also the [postMessage demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/post_messages)
*

View File

@ -2,7 +2,7 @@ import { ModelType } from '../../../BaseModel';
import Plugin from '../Plugin';
import { Path } from './types';
/**
* This module provides access to the Joplin data API: https://joplinapp.org/api/references/rest_api/
* This module provides access to the Joplin data API: https://joplinapp.org/help/api/references/rest_api
* This is the main way to retrieve data, such as notes, notebooks, tags, etc.
* or to update them or delete them.
*
@ -13,12 +13,12 @@ import { Path } from './types';
* In general you would use the methods in this class as if you were using a REST API. There are four methods that map to GET, POST, PUT and DELETE calls.
* And each method takes these parameters:
*
* * `path`: This is an array that represents the path to the resource in the form `["resouceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
* * `path`: This is an array that represents the path to the resource in the form `["resourceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
* * `query`: (Optional) The query parameters. In a URL, this is the part after the question mark "?". In this case, it should be an object with key/value pairs.
* * `data`: (Optional) Applies to PUT and POST calls only. The request body contains the data you want to create or modify, for example the content of a note or folder.
* * `files`: (Optional) Used to create new resources and associate them with files.
*
* Please refer to the [Joplin API documentation](https://joplinapp.org/api/references/rest_api/) for complete details about each call. As the plugin runs within the Joplin application **you do not need an authorisation token** to use this API.
* Please refer to the [Joplin API documentation](https://joplinapp.org/help/api/references/rest_api) for complete details about each call. As the plugin runs within the Joplin application **you do not need an authorisation token** to use this API.
*
* For example:
*

View File

@ -1,3 +1,4 @@
import { FilterHandler } from '../../../eventManager';
/**
* @ignore
*
@ -5,6 +6,6 @@
* so for now disable filters.
*/
export default class JoplinFilters {
on(name: string, callback: Function): Promise<void>;
off(name: string, callback: Function): Promise<void>;
on(name: string, callback: FilterHandler): Promise<void>;
off(name: string, callback: FilterHandler): Promise<void>;
}

View File

@ -1,12 +1,33 @@
import { Rectangle } from './types';
export interface Implementation {
nativeImage: any;
}
export interface CreateFromBufferOptions {
width?: number;
height?: number;
scaleFactor?: number;
}
export interface CreateFromPdfOptions {
/**
* The first page to export. Defaults to `1`, the first page in
* the document.
*/
minPage?: number;
/**
* The number of the last page to convert. Defaults to the last page
* if not given.
*
* If `maxPage` is greater than the number of pages in the PDF, all pages
* in the PDF will be converted to images.
*/
maxPage?: number;
scaleFactor?: number;
}
export interface PdfInfo {
pageCount: number;
}
export interface Implementation {
createFromPath: (path: string) => Promise<unknown>;
createFromPdf: (path: string, options: CreateFromPdfOptions) => Promise<unknown[]>;
getPdfInfo: (path: string) => Promise<PdfInfo>;
}
export interface ResizeOptions {
width?: number;
height?: number;
@ -24,6 +45,7 @@ export type Handle = string;
* [View the
* example](https://github.com/laurent22/joplin/blob/dev/packages/app-cli/tests/support/plugins/imaging/src/index.ts)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinImaging {
private implementation_;
@ -32,11 +54,20 @@ export default class JoplinImaging {
private createImageHandle;
private imageByHandle;
private cacheImage;
/**
* Creates an image from the provided path. Note that images and PDFs are supported. If you
* provide a URL instead of a local path, the file will be downloaded first then converted to an
* image.
*/
createFromPath(filePath: string): Promise<Handle>;
createFromResource(resourceId: string): Promise<Handle>;
createFromPdfPath(path: string, options?: CreateFromPdfOptions): Promise<Handle[]>;
createFromPdfResource(resourceId: string, options?: CreateFromPdfOptions): Promise<Handle[]>;
getPdfInfoFromPath(path: string): Promise<PdfInfo>;
getPdfInfoFromResource(resourceId: string): Promise<PdfInfo>;
getSize(handle: Handle): Promise<any>;
resize(handle: Handle, options?: ResizeOptions): Promise<string>;
crop(handle: Handle, rectange: Rectangle): Promise<string>;
crop(handle: Handle, rectangle: Rectangle): Promise<string>;
toPngFile(handle: Handle, filePath: string): Promise<void>;
/**
* Quality is between 0 and 100
@ -57,5 +88,5 @@ export default class JoplinImaging {
* Image data is not automatically deleted by Joplin so make sure you call
* this method on the handle once you are done.
*/
free(handle: Handle): Promise<void>;
free(handles: Handle[] | Handle): Promise<void>;
}

View File

@ -9,7 +9,10 @@ import { ExportModule, ImportModule } from './types';
*
* See the documentation of the [[ExportModule]] and [[ImportModule]] for more information.
*
* You may also want to refer to the Joplin API documentation to see the list of properties for each item (note, notebook, etc.) - https://joplinapp.org/api/references/rest_api/
* You may also want to refer to the Joplin API documentation to see the list of properties for each item (note, notebook, etc.) - https://joplinapp.org/help/api/references/rest_api
*
* <span class="platform-desktop">desktop</span>: While it is possible to register import and export
* modules on mobile, there is no GUI to activate them.
*/
export default class JoplinInterop {
registerExportModule(module: ExportModule): Promise<void>;

View File

@ -19,8 +19,6 @@ export type ChangeHandler = (event: ChangeEvent) => void;
export default class JoplinSettings {
private plugin_;
constructor(plugin: Plugin);
private get keyPrefix();
private namespacedKey;
/**
* Registers new settings.
* Note that registering a setting item is dynamic and will be gone next time Joplin starts.
@ -40,6 +38,12 @@ export default class JoplinSettings {
*/
registerSection(name: string, section: SettingSection): Promise<void>;
/**
* Gets setting values (only applies to setting you registered from your plugin)
*/
values(keys: string[] | string): Promise<Record<string, unknown>>;
/**
* @deprecated Use joplin.settings.values()
*
* Gets a setting value (only applies to setting you registered from your plugin)
*/
value(key: string): Promise<any>;

View File

@ -5,6 +5,7 @@ import JoplinViewsMenus from './JoplinViewsMenus';
import JoplinViewsToolbarButtons from './JoplinViewsToolbarButtons';
import JoplinViewsPanels from './JoplinViewsPanels';
import JoplinViewsNoteList from './JoplinViewsNoteList';
import JoplinViewsEditors from './JoplinViewsEditor';
/**
* This namespace provides access to view-related services.
*
@ -19,11 +20,13 @@ export default class JoplinViews {
private menus_;
private toolbarButtons_;
private dialogs_;
private editors_;
private noteList_;
private implementation_;
constructor(implementation: any, plugin: Plugin, store: any);
get dialogs(): JoplinViewsDialogs;
get panels(): JoplinViewsPanels;
get editors(): JoplinViewsEditors;
get menuItems(): JoplinViewsMenuItems;
get menus(): JoplinViewsMenus;
get toolbarButtons(): JoplinViewsToolbarButtons;

View File

@ -43,6 +43,14 @@ export default class JoplinViewsDialogs {
* Displays a message box with OK/Cancel buttons. Returns the button index that was clicked - "0" for OK and "1" for "Cancel"
*/
showMessageBox(message: string): Promise<number>;
/**
* Displays a dialog to select a file or a directory. Same options and
* output as
* https://www.electronjs.org/docs/latest/api/dialog#dialogshowopendialogbrowserwindow-options
*
* <span class="platform-desktop">desktop</span>
*/
showOpenDialog(options: any): Promise<any>;
/**
* Sets the dialog HTML content
*/
@ -56,7 +64,9 @@ export default class JoplinViewsDialogs {
*/
setButtons(handle: ViewHandle, buttons: ButtonSpec[]): Promise<ButtonSpec[]>;
/**
* Opens the dialog
* Opens the dialog.
*
* On desktop, this closes any copies of the dialog open in different windows.
*/
open(handle: ViewHandle): Promise<DialogResult>;
/**

View File

@ -0,0 +1,88 @@
import Plugin from '../Plugin';
import { ActivationCheckCallback, ViewHandle, UpdateCallback } from './types';
/**
* Allows creating alternative note editors. You can create a view to handle loading and saving the
* note, and do your own rendering.
*
* Although it may be used to implement an alternative text editor, the more common use case may be
* to render the note in a different, graphical way - for example displaying a graph, and
* saving/loading the graph data in the associated note. In that case, you would detect whether the
* current note contains graph data and, in this case, you'd display your viewer.
*
* Terminology: An editor is **active** when it can be used to edit the current note. Note that it
* doesn't necessarily mean that your editor is visible - it just means that the user has the option
* to switch to it (via the "toggle editor" button). A **visible** editor is active and is currently
* being displayed.
*
* To implement an editor you need to listen to two events:
*
* - `onActivationCheck`: This is a way for the app to know whether your editor should be active or
* not. Return `true` from this handler to activate your editor.
*
* - `onUpdate`: When this is called you should update your editor based on the current note
* content. Call `joplin.workspace.selectedNote()` to get the current note.
*
* - `showEditorPlugin` and `toggleEditorPlugin` commands. Additionally you can use these commands
* to display your editor via `joplin.commands.execute('showEditorPlugin')`. This is not always
* necessary since the user can switch to your editor using the "toggle editor" button, however
* you may want to programmatically display the editor in some cases - for example when creating a
* new note specific to your editor.
*
* Note that only one editor view can be active at a time. This is why it is important not to
* activate your view if it's not relevant to the current note. If more than one is active, it is
* undefined which editor is going to be used to display the note.
*
* For an example of editor plugin, see the [YesYouKan
* plugin](https://github.com/joplin/plugin-yesyoukan/blob/master/src/index.ts). In particular,
* check the logic around `onActivationCheck` and `onUpdate` since this is the entry points for
* using this API.
*/
export default class JoplinViewsEditors {
private store;
private plugin;
private activationCheckHandlers_;
constructor(plugin: Plugin, store: any);
private controller;
/**
* Creates a new editor view
*/
create(id: string): Promise<ViewHandle>;
/**
* Sets the editor HTML content
*/
setHtml(handle: ViewHandle, html: string): Promise<string>;
/**
* Adds and loads a new JS or CSS file into the panel.
*/
addScript(handle: ViewHandle, scriptPath: string): Promise<void>;
/**
* See [[JoplinViewPanels]]
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Emitted when the editor can potentially be activated - this for example when the current note
* is changed, or when the application is opened. At that point should can check the current
* note and decide whether your editor should be activated or not. If it should return `true`,
* otherwise return `false`.
*/
onActivationCheck(handle: ViewHandle, callback: ActivationCheckCallback): Promise<void>;
/**
* Emitted when the editor content should be updated. This for example when the currently
* selected note changes, or when the user makes the editor visible.
*/
onUpdate(handle: ViewHandle, callback: UpdateCallback): Promise<void>;
/**
* See [[JoplinViewPanels]]
*/
postMessage(handle: ViewHandle, message: any): void;
/**
* Tells whether the editor is active or not.
*/
isActive(handle: ViewHandle): Promise<boolean>;
/**
* Tells whether the editor is effectively visible or not. If the editor is inactive, this will
* return `false`. If the editor is active and the user has switched to it, it will return
* `true`. Otherwise it will return `false`.
*/
isVisible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -4,6 +4,8 @@ import Plugin from '../Plugin';
* Allows creating and managing menu items.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/register_command)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsMenuItems {
private store;

View File

@ -4,6 +4,8 @@ import Plugin from '../Plugin';
* Allows creating menus.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/menu)
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsMenus {
private store;

View File

@ -1,6 +1,39 @@
import { Store } from 'redux';
import Plugin from '../Plugin';
import { ListRenderer } from './noteListType';
/**
* This API allows you to customise how each note in the note list is rendered.
* The renderer you implement follows a unidirectional data flow.
*
* The app provides the required dependencies whenever a note is updated - you
* process these dependencies, and return some props, which are then passed to
* your template and rendered. See [[ListRenderer]] for a detailed description
* of each property of the renderer.
*
* ## Reference
*
* * [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/note_list_renderer)
*
* * [Default simple renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultListRenderer.ts)
*
* * [Default detailed renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultMultiColumnsRenderer.ts)
*
* ## Screenshots:
*
* ### Top to bottom with title, date and body
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/TopToBottom.png"/>
*
* ### Left to right with thumbnails
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/LeftToRight_Thumbnails.png"/>
*
* ### Top to bottom with editable title
*
* <img width="250px" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/note_list/TopToBottom_Editable.png"/>
*
* <span class="platform-desktop">desktop</span>
*/
export default class JoplinViewsNoteList {
private plugin_;
private store_;

View File

@ -1,12 +1,17 @@
import Plugin from '../Plugin';
import { ViewHandle } from './types';
/**
* Allows creating and managing view panels. View panels currently are
* displayed at the right of the sidebar and allows displaying any HTML
* content (within a webview) and update it in real-time. For example it
* Allows creating and managing view panels. View panels allow displaying any HTML
* content (within a webview) and updating it in real-time. For example it
* could be used to display a table of content for the active note, or
* display various metadata or graph.
*
* On desktop, view panels currently are displayed at the right of the sidebar, though can
* be moved with "View" > "Change application layout".
*
* On mobile, view panels are shown in a tabbed dialog that can be opened using a
* toolbar button.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/toc)
*/
export default class JoplinViewsPanels {
@ -75,4 +80,5 @@ export default class JoplinViewsPanels {
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
isActive(handle: ViewHandle): Promise<boolean>;
}

Some files were not shown because too many files have changed in this diff Show More