1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Plugins: Add support for hiding and showing panels

This commit is contained in:
Laurent Cozic 2021-01-02 13:32:15 +00:00
parent 0be8cdf760
commit 5b295d5f6f
25 changed files with 298 additions and 17 deletions

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -1,4 +1,5 @@
import joplin from 'api';
import { ToolbarButtonLocation } from 'api/types';
const uslug = require('uslug');
@ -91,6 +92,18 @@ joplin.plugins.register({
updateTocView();
});
await joplin.commands.register({
name: 'toggleToc',
label: 'Toggle TOC',
iconName: 'fas fa-drum',
execute: async () => {
const isVisible = await (panels as any).visible(view);
(panels as any).show(view, !isVisible);
},
});
await joplin.views.toolbarButtons.create('toggleToc', 'toggleToc', ToolbarButtonLocation.NoteToolbar);
updateTocView();
},
});

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -22,6 +22,9 @@ import { LayoutItem } from './gui/ResizableLayout/utils/types';
import stateToWhenClauseContext from './services/commands/stateToWhenClauseContext';
import ResourceService from '@joplin/lib/services/ResourceService';
import ExternalEditWatcher from '@joplin/lib/services/ExternalEditWatcher';
import produce from 'immer';
import iterateItems from './gui/ResizableLayout/utils/iterateItems';
import validateLayout from './gui/ResizableLayout/utils/validateLayout';
const { FoldersScreenUtils } = require('@joplin/lib/folders-screen-utils.js');
const MasterKey = require('@joplin/lib/models/MasterKey');
@ -247,6 +250,29 @@ class Application extends BaseApplication {
};
break;
case 'MAIN_LAYOUT_SET_ITEM_PROP':
{
let newLayout = produce(state.mainLayout, (draftLayout: LayoutItem) => {
iterateItems(draftLayout, (_itemIndex: number, item: LayoutItem, _parent: LayoutItem) => {
if (item.key === action.itemKey) {
(item as any)[action.propName] = action.propValue;
return false;
}
return true;
});
});
if (newLayout !== state.mainLayout) newLayout = validateLayout(newLayout);
newState = {
...state,
mainLayout: newLayout,
};
}
break;
case 'NOTE_FILE_WATCHER_ADD':
if (newState.watchedNoteFiles.indexOf(action.id) < 0) {

View File

@ -16,8 +16,4 @@ export default function findItemByKey(layout: LayoutItem, key: string): LayoutIt
}
return recurseFind(layout);
// const output = recurseFind(layout);
// if (!output) throw new Error(`Could not find item "${key}"`);
// return output;
}

View File

@ -2,6 +2,8 @@ import { LayoutItem } from './types';
type ItemItemCallback = (itemIndex: number, item: LayoutItem, parent: LayoutItem)=> boolean;
// Callback should return `true` if iteration should continue, or `false` if it
// should stop
export default function iterateItems(layout: LayoutItem, callback: ItemItemCallback) {
const result = callback(0, layout, null);
if (result === false) return;

View File

@ -4,5 +4,5 @@
# It could be used to develop plugins too.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
PLUGIN_PATH="$SCRIPT_DIR/../app-cli/tests/support/plugins/register_command"
PLUGIN_PATH="$SCRIPT_DIR/../app-cli/tests/support/plugins/toc"
npm i --prefix="$PLUGIN_PATH" && npm start -- --dev-plugins "$PLUGIN_PATH"

View File

@ -30,4 +30,16 @@ export default class JoplinViewsPanels {
* Called when a message is sent from the webview (using postMessage).
*/
onMessage(handle: ViewHandle, callback: Function): Promise<void>;
/**
* Shows the panel
*/
show(handle: ViewHandle, show?: boolean): Promise<void>;
/**
* Hides the panel
*/
hide(handle: ViewHandle): Promise<void>;
/**
* Tells whether the panel is visible or not
*/
visible(handle: ViewHandle): Promise<boolean>;
}

View File

@ -1,6 +1,6 @@
{
"name": "generator-joplin",
"version": "1.5.3",
"version": "1.6.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -141,7 +141,7 @@ class Note extends BaseItem {
useAbsolutePaths: false,
}, options);
this.logger().debug('replaceResourceInternalToExternalLinks', 'options:', options, 'body:', body);
// this.logger().debug('replaceResourceInternalToExternalLinks', 'options:', options, 'body:', body);
const resourceIds = await this.linkedResourceIds(body);
const Resource = this.getClass('Resource');
@ -161,7 +161,7 @@ class Note extends BaseItem {
body = body.replace(new RegExp(`:/${id}`, 'gi'), markdownUtils.escapeLinkUrl(resourcePath));
}
this.logger().debug('replaceResourceInternalToExternalLinks result', body);
// this.logger().debug('replaceResourceInternalToExternalLinks result', body);
return body;
}
@ -194,7 +194,7 @@ class Note extends BaseItem {
pathsToTry = temp;
this.logger().debug('replaceResourceExternalToInternalLinks', 'options:', options, 'pathsToTry:', pathsToTry);
// this.logger().debug('replaceResourceExternalToInternalLinks', 'options:', options, 'pathsToTry:', pathsToTry);
for (const basePath of pathsToTry) {
const reStrings = [

View File

@ -6,14 +6,14 @@ export default class ViewController {
private pluginId_: string;
private store_: any;
constructor(handle: ViewHandle, pluginId: string, store: any) {
public constructor(handle: ViewHandle, pluginId: string, store: any) {
this.handle_ = handle;
this.pluginId_ = pluginId;
this.store_ = store;
}
protected get storeView(): any {
return this.store_.pluginService.plugins[this.pluginId_].views[this.handle];
return this.store_.getState().pluginService.plugins[this.pluginId_].views[this.handle];
}
protected get store(): any {

View File

@ -17,13 +17,33 @@ interface CloseResponse {
reject: Function;
}
// TODO: Copied from:
// packages/app-desktop/gui/ResizableLayout/utils/findItemByKey.ts
function findItemByKey(layout: any, key: string): any {
if (!layout) throw new Error('Layout cannot be null');
function recurseFind(item: any): any {
if (item.key === key) return item;
if (item.children) {
for (const child of item.children) {
const found = recurseFind(child);
if (found) return found;
}
}
return null;
}
return recurseFind(layout);
}
export default class WebviewController extends ViewController {
private baseDir_: string;
private messageListener_: Function = null;
private closeResponse_: CloseResponse = null;
constructor(id: string, pluginId: string, store: any, baseDir: string, containerType: ContainerType) {
public constructor(id: string, pluginId: string, store: any, baseDir: string, containerType: ContainerType) {
super(id, pluginId, store);
this.baseDir_ = toSystemSlashes(baseDir, 'linux');
@ -91,6 +111,29 @@ export default class WebviewController extends ViewController {
this.messageListener_ = callback;
}
// ---------------------------------------------
// Specific to panels
// ---------------------------------------------
public async show(show: boolean = true): Promise<void> {
this.store.dispatch({
type: 'MAIN_LAYOUT_SET_ITEM_PROP',
itemKey: this.handle,
propName: 'visible',
propValue: show,
});
}
public async hide(): Promise<void> {
return this.show(false);
}
public get visible(): boolean {
const mainLayout = this.store.getState().mainLayout;
const item = findItemByKey(mainLayout, this.handle);
return item ? item.visible : false;
}
// ---------------------------------------------
// Specific to dialogs
// ---------------------------------------------

View File

@ -17,7 +17,7 @@ export default class JoplinViewsPanels {
private store: any;
private plugin: Plugin;
constructor(plugin: Plugin, store: any) {
public constructor(plugin: Plugin, store: any) {
this.store = store;
this.plugin = plugin;
}
@ -29,7 +29,7 @@ export default class JoplinViewsPanels {
/**
* Creates a new panel
*/
async create(id: string): Promise<ViewHandle> {
public async create(id: string): Promise<ViewHandle> {
if (!id) {
this.plugin.deprecationNotice('1.5', 'Creating a view without an ID is deprecated. To fix it, change your call to `joplin.views.panels.create("my-unique-id")`');
id = `${this.plugin.viewCount}`;
@ -44,22 +44,43 @@ export default class JoplinViewsPanels {
/**
* Sets the panel webview HTML
*/
async setHtml(handle: ViewHandle, html: string) {
public async setHtml(handle: ViewHandle, html: string) {
return this.controller(handle).html = html;
}
/**
* Adds and loads a new JS or CSS files into the panel.
*/
async addScript(handle: ViewHandle, scriptPath: string) {
public async addScript(handle: ViewHandle, scriptPath: string) {
return this.controller(handle).addScript(scriptPath);
}
/**
* Called when a message is sent from the webview (using postMessage).
*/
async onMessage(handle: ViewHandle, callback: Function) {
public async onMessage(handle: ViewHandle, callback: Function) {
return this.controller(handle).onMessage(callback);
}
/**
* Shows the panel
*/
public async show(handle: ViewHandle, show: boolean = true): Promise<void> {
await this.controller(handle).show(show);
}
/**
* Hides the panel
*/
public async hide(handle: ViewHandle): Promise<void> {
await this.show(handle, false);
}
/**
* Tells whether the panel is visible or not
*/
public async visible(handle: ViewHandle): Promise<boolean> {
return this.controller(handle).visible;
}
}