Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
JackGruber committed Dec 4, 2023
2 parents 07fafb3 + cde1ec9 commit 021085c
Show file tree
Hide file tree
Showing 27 changed files with 23,209 additions and 13,986 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## not released

## v1.3.4 (2023-12-04)

- Fix: #61 On Jex backup, do not overwrite already exported notebooks if the notebooks name differs only in special characters
- Fix: #62 Better error message if the Joplin profile directory is set as backup path
- Update en_US translation by @montoner0

## v1.3.3 (2023-07-08)

- Add: Workaround for bug #132 with `"` (double quotes) in the password where zip files with such a password can no longer be opened
Expand Down
29 changes: 21 additions & 8 deletions GENERATOR_DOC.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# generator-joplin
# Plugin development

Scaffolds out a new Joplin plugin
This documentation describes how to create a plugin, and how to work with the plugin builder framework and API.

## Installation

Expand All @@ -14,14 +14,9 @@ npm install -g generator-joplin
Then generate your new project:

```bash
yo joplin
yo --node-package-manager npm joplin
```

## Development

To test the generator for development purposes, follow the instructions there: https://yeoman.io/authoring/#running-the-generator
This is a template to create a new Joplin plugin.

## Structure

The main two files you will want to look at are:
Expand All @@ -39,6 +34,10 @@ To build the plugin, simply run `npm run dist`.

The project is setup to use TypeScript, although you can change the configuration to use plain JavaScript.

## Updating the manifest version number

You can run `npm run updateVersion` to bump the patch part of the version number, so for example 1.0.3 will become 1.0.4. This script will update both the package.json and manifest.json version numbers so as to keep them in sync.

## Publishing the plugin

To publish the plugin, add it to npmjs.com by running `npm publish`. Later on, a script will pick up your plugin and add it automatically to the Joplin plugin repository as long as the package satisfies these conditions:
Expand All @@ -57,6 +56,13 @@ In general this command tries to do the right thing - in particular it's going t

The file that may cause problem is "webpack.config.js" because it's going to be overwritten. For that reason, if you want to change it, consider creating a separate JavaScript file and include it in webpack.config.js. That way, when you update, you only have to restore the line that include your file.

### Simple backup changes to `webpack.config.js`

To support including `7zip-bin` in the plugin's built `.jpl` file, the following changes are made:

- Added `node: { __dirname: 'mock' },` to the plugin `baseConfig`. This causes `7zip-bin` to return a more correct path to `7za` (e.g. `/linux/x64/7za` instead of `/tmp/.mount_Joplin/resources/app.asar/services/plugins/linux/x64/7za`).
- Added a `new CopyPlugin({ ... })` to `pluginConfig`'s `plugins` object to copy `7zip-bin` from `node_modules` to the `dist` directory.

## External script files

By default, the compiler (webpack) is going to compile `src/index.ts` only (as well as any file it imports), and any other file will simply be copied to the plugin package. In some cases this is sufficient, however if you have [content scripts](https://joplinapp.org/api/references/plugin_api/classes/joplincontentscripts.html) or [webview scripts](https://joplinapp.org/api/references/plugin_api/classes/joplinviewspanels.html#addscript) you might want to compile them too, in particular in these two cases:
Expand All @@ -67,6 +73,13 @@ By default, the compiler (webpack) is going to compile `src/index.ts` only (as w

To get such an external script file to compile, you need to add it to the `extraScripts` array in `plugin.config.json`. The path you add should be relative to /src. For example, if you have a file in "/src/webviews/index.ts", the path should be set to "webviews/index.ts". Once compiled, the file will always be named with a .js extension. So you will get "webviews/index.js" in the plugin package, and that's the path you should use to reference the file.

## More information

- [Joplin Plugin API](https://joplinapp.org/api/references/plugin_api/classes/joplin.html)
- [Joplin Data API](https://joplinapp.org/help/api/references/rest_api)
- [Joplin Plugin Manifest](https://joplinapp.org/api/references/plugin_manifest/)
- Ask for help on the [forum](https://discourse.joplinapp.org/) or our [Discord channel](https://discord.gg/VSj7AFHvpq)

## License

MIT © Laurent Cozic
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A plugin to extend Joplin with a manual and automatic backup function.
<!-- markdownlint-disable MD028 -->
<!-- markdownlint-disable MD007 -->

<img src=img/main.jpg>
<img src=img/main.png>

<!-- prettier-ignore-start -->
<!-- TOC depthfrom:2 orderedlist:false -->
Expand Down
4 changes: 3 additions & 1 deletion __test__/backup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import * as path from "path";
import { when } from "jest-when";
import { sevenZip } from "../src/sevenZip";
import joplin from "api";
import { I18n } from "i18n";

function getTestPaths(): any {
const testPath: any = {};
Expand Down Expand Up @@ -58,6 +57,7 @@ describe("Backup", function () {
when(spyOnGlobalValue)
.mockImplementation(() => Promise.resolve("no mockImplementation"))
.calledWith("profileDir").mockImplementation(() => Promise.resolve(testPath.joplinProfile))
.calledWith("locale").mockImplementation(() => Promise.resolve("en_US"))
.calledWith("templateDir").mockImplementation(() => Promise.resolve(testPath.templates));

await createTestStructure();
Expand All @@ -81,6 +81,8 @@ describe("Backup", function () {
spyOnShowError = jest
.spyOn(backup, "showError")
.mockImplementation(() => {});

await backup.confLocale(path.join(__dirname, "..", "src", "locales"));
});

afterEach(async () => {
Expand Down
9 changes: 7 additions & 2 deletions api/Joplin.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import JoplinSettings from './JoplinSettings';
import JoplinContentScripts from './JoplinContentScripts';
import JoplinClipboard from './JoplinClipboard';
import JoplinWindow from './JoplinWindow';
import BasePlatformImplementation from '../BasePlatformImplementation';
import JoplinImaging from './JoplinImaging';
/**
* This is the main entry point to the Joplin API. You can access various services using the provided accessors.
*
Expand All @@ -25,6 +27,7 @@ import JoplinWindow from './JoplinWindow';
export default class Joplin {
private data_;
private plugins_;
private imaging_;
private workspace_;
private filters_;
private commands_;
Expand All @@ -34,9 +37,11 @@ export default class Joplin {
private contentScripts_;
private clipboard_;
private window_;
constructor(implementation: any, plugin: Plugin, store: any);
private implementation_;
constructor(implementation: BasePlatformImplementation, plugin: Plugin, store: any);
get data(): JoplinData;
get clipboard(): JoplinClipboard;
get imaging(): JoplinImaging;
get window(): JoplinWindow;
get plugins(): JoplinPlugins;
get workspace(): JoplinWorkspace;
Expand All @@ -52,7 +57,6 @@ export default class Joplin {
get views(): JoplinViews;
get interop(): JoplinInterop;
get settings(): JoplinSettings;
get versionInfo(): any;
/**
* It is not possible to bundle native packages with a plugin, because they
* need to work cross-platforms. Instead access to certain useful native
Expand All @@ -66,4 +70,5 @@ export default class Joplin {
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/nativeModule)
*/
require(_path: string): any;
versionInfo(): Promise<import("./types").VersionInfo>;
}
27 changes: 25 additions & 2 deletions api/JoplinData.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
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.
*
Expand All @@ -17,7 +18,7 @@ import { Path } from './types';
* * `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:
*
Expand All @@ -39,6 +40,8 @@ import { Path } from './types';
export default class JoplinData {
private api_;
private pathSegmentRegex_;
private plugin;
constructor(plugin: Plugin);
private serializeApiBody;
private pathToString;
get(path: Path, query?: any): Promise<any>;
Expand All @@ -47,4 +50,24 @@ export default class JoplinData {
delete(path: Path, query?: any): Promise<any>;
itemType(itemId: string): Promise<ModelType>;
resourcePath(resourceId: string): Promise<string>;
/**
* Gets an item user data. User data are key/value pairs. The `key` can be any
* arbitrary string, while the `value` can be of any type supported by
* [JSON.stringify](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description)
*
* User data is synchronised across devices, and each value wil be merged based on their timestamp:
*
* - If value is modified by client 1, then modified by client 2, it will take the value from client 2
* - If value is modified by client 1, then deleted by client 2, the value will be deleted after merge
* - If value is deleted by client 1, then updated by client 2, the value will be restored and set to the value from client 2 after merge
*/
userDataGet<T>(itemType: ModelType, itemId: string, key: string): Promise<T>;
/**
* Sets a note user data. See {@link JoplinData.userDataGet} for more details.
*/
userDataSet<T>(itemType: ModelType, itemId: string, key: string, value: T): Promise<void>;
/**
* Deletes a note user data. See {@link JoplinData.userDataGet} for more details.
*/
userDataDelete(itemType: ModelType, itemId: string, key: string): Promise<void>;
}
61 changes: 61 additions & 0 deletions api/JoplinImaging.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Rectangle } from './types';
export interface Implementation {
nativeImage: any;
}
export interface CreateFromBufferOptions {
width?: number;
height?: number;
scaleFactor?: number;
}
export interface ResizeOptions {
width?: number;
height?: number;
quality?: 'good' | 'better' | 'best';
}
export type Handle = string;
/**
* Provides imaging functions to resize or process images. You create an image
* using one of the `createFrom` functions, then use the other functions to
* process the image.
*
* Images are associated with a handle which is what will be available to the
* plugin. Once you are done with an image, free it using the `free()` function.
*
* [View the
* example](https://github.com/laurent22/joplin/blob/dev/packages/app-cli/tests/support/plugins/imaging/src/index.ts)
*
*/
export default class JoplinImaging {
private implementation_;
private images_;
constructor(implementation: Implementation);
private createImageHandle;
private imageByHandle;
private cacheImage;
createFromPath(filePath: string): Promise<Handle>;
createFromResource(resourceId: string): Promise<Handle>;
getSize(handle: Handle): Promise<any>;
resize(handle: Handle, options?: ResizeOptions): Promise<string>;
crop(handle: Handle, rectange: Rectangle): Promise<string>;
toPngFile(handle: Handle, filePath: string): Promise<void>;
/**
* Quality is between 0 and 100
*/
toJpgFile(handle: Handle, filePath: string, quality?: number): Promise<void>;
private tempFilePath;
/**
* Creates a new Joplin resource from the image data. The image will be
* first converted to a JPEG.
*/
toJpgResource(handle: Handle, resourceProps: any, quality?: number): Promise<import("../../database/types").ResourceEntity>;
/**
* Creates a new Joplin resource from the image data. The image will be
* first converted to a PNG.
*/
toPngResource(handle: Handle, resourceProps: any): Promise<import("../../database/types").ResourceEntity>;
/**
* 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>;
}
2 changes: 1 addition & 1 deletion api/JoplinInterop.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ 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
*/
export default class JoplinInterop {
registerExportModule(module: ExportModule): Promise<void>;
Expand Down
5 changes: 2 additions & 3 deletions api/JoplinSettings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ export interface ChangeEvent {
*/
keys: string[];
}
export declare type ChangeHandler = (event: ChangeEvent) => void;
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.
*
Expand All @@ -19,8 +20,6 @@ export declare 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.
Expand Down
5 changes: 4 additions & 1 deletion api/JoplinViews.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import JoplinViewsMenuItems from './JoplinViewsMenuItems';
import JoplinViewsMenus from './JoplinViewsMenus';
import JoplinViewsToolbarButtons from './JoplinViewsToolbarButtons';
import JoplinViewsPanels from './JoplinViewsPanels';
import JoplinViewsNoteList from './JoplinViewsNoteList';
/**
* This namespace provides access to view-related services.
*
Expand All @@ -13,16 +14,18 @@ import JoplinViewsPanels from './JoplinViewsPanels';
export default class JoplinViews {
private store;
private plugin;
private dialogs_;
private panels_;
private menuItems_;
private menus_;
private toolbarButtons_;
private dialogs_;
private noteList_;
private implementation_;
constructor(implementation: any, plugin: Plugin, store: any);
get dialogs(): JoplinViewsDialogs;
get panels(): JoplinViewsPanels;
get menuItems(): JoplinViewsMenuItems;
get menus(): JoplinViewsMenus;
get toolbarButtons(): JoplinViewsToolbarButtons;
get noteList(): JoplinViewsNoteList;
}
6 changes: 6 additions & 0 deletions api/JoplinViewsDialogs.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ 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
*/
showOpenDialog(options: any): Promise<any>;
/**
* Sets the dialog HTML content
*/
Expand Down
24 changes: 24 additions & 0 deletions api/JoplinViewsNoteList.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
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.
*
* [View the demo plugin](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/note_list_renderer)
*
* The default list renderer is implemented using the same API, so it worth checking it too:
*
* [Default list renderer](https://github.com/laurent22/joplin/tree/dev/packages/lib/services/noteList/defaultListRenderer.ts)
*/
export default class JoplinViewsNoteList {
private plugin_;
private store_;
constructor(plugin: Plugin, store: Store);
registerRenderer(renderer: ListRenderer): Promise<void>;
}
8 changes: 4 additions & 4 deletions api/JoplinWorkspace.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Disposable, MenuItem } from './types';
export interface EditContextMenuFilterObject {
items: MenuItem[];
}
declare type FilterHandler<T> = (object: T) => Promise<void>;
type FilterHandler<T> = (object: T) => Promise<void>;
declare enum ItemChangeEventType {
Create = 1,
Update = 2,
Expand All @@ -19,9 +19,9 @@ interface SyncStartEvent {
interface ResourceChangeEvent {
id: string;
}
declare type ItemChangeHandler = (event: ItemChangeEvent) => void;
declare type SyncStartHandler = (event: SyncStartEvent) => void;
declare type ResourceChangeHandler = (event: ResourceChangeEvent) => void;
type ItemChangeHandler = (event: ItemChangeEvent) => void;
type SyncStartHandler = (event: SyncStartEvent) => void;
type ResourceChangeHandler = (event: ResourceChangeEvent) => void;
/**
* 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
Expand Down
Loading

0 comments on commit 021085c

Please sign in to comment.