1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-12-29 23:48:19 +02:00

Compare commits

...

12 Commits

Author SHA1 Message Date
Laurent Cozic
6001e07cbc update 2023-07-31 19:00:21 +01:00
Laurent Cozic
6210d85192 Merge branch 'dev' into mobile_plugins_2 2023-07-31 11:12:44 +01:00
Laurent Cozic
2633bcef69 Doc: Shortened section about carbon neutrality and mentioned data being in France 2023-07-31 11:12:32 +01:00
renovate[bot]
772c8abdcf Update dependency react-native-safe-area-context to v4.6.0 (#8586)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-31 10:31:31 +01:00
Joplin Bot
ac098759ea Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-07-31 00:44:28 +00:00
Naoki Kawamukai
349dda30b8 All: Translation: Update ja_JP.po (#8580) 2023-07-30 18:35:37 -04:00
renovate[bot]
cbbd9b9a61 Update dependency react-native-image-picker to v5.6.0 (#8582)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-30 15:22:23 +01:00
github-actions[bot]
14ef0d725b @kna has signed the CLA in laurent22/joplin#8580 2023-07-30 02:10:58 +00:00
Laurent Cozic
0c981ae4a7 fixed module import 2023-07-29 19:19:01 +01:00
Laurent Cozic
401eee568a fixed JoplinWindow 2023-07-29 17:43:58 +01:00
Laurent Cozic
0b85e16125 Merge branch 'dev' into mobile_plugins_2 2023-07-29 17:34:12 +01:00
Laurent Cozic
0368c26ead init 2023-07-28 21:21:13 +01:00
41 changed files with 16300 additions and 97 deletions

View File

@@ -76,6 +76,7 @@ plugin_types/
readme/
packages/react-native-vosk/lib/
packages/lib/countable/Countable.js
packages/app-mobile/plugins
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
packages/app-cli/app/LinkSelector.js
@@ -443,6 +444,7 @@ packages/app-mobile/root.js
packages/app-mobile/services/AlarmServiceDriver.android.js
packages/app-mobile/services/AlarmServiceDriver.ios.js
packages/app-mobile/services/e2ee/RSA.react-native.js
packages/app-mobile/services/plugins/PluginRunner.js
packages/app-mobile/services/profiles/index.js
packages/app-mobile/services/voiceTyping/vosk.android.js
packages/app-mobile/services/voiceTyping/vosk.ios.js
@@ -456,6 +458,7 @@ packages/app-mobile/utils/checkPermissions.js
packages/app-mobile/utils/createRootStyle.js
packages/app-mobile/utils/debounce.js
packages/app-mobile/utils/fs-driver-rn.js
packages/app-mobile/utils/markupLanguageUtils.js
packages/app-mobile/utils/setupNotifications.js
packages/app-mobile/utils/shareHandler.js
packages/app-mobile/utils/types.js

2
.gitignore vendored
View File

@@ -428,6 +428,7 @@ packages/app-mobile/root.js
packages/app-mobile/services/AlarmServiceDriver.android.js
packages/app-mobile/services/AlarmServiceDriver.ios.js
packages/app-mobile/services/e2ee/RSA.react-native.js
packages/app-mobile/services/plugins/PluginRunner.js
packages/app-mobile/services/profiles/index.js
packages/app-mobile/services/voiceTyping/vosk.android.js
packages/app-mobile/services/voiceTyping/vosk.ios.js
@@ -441,6 +442,7 @@ packages/app-mobile/utils/checkPermissions.js
packages/app-mobile/utils/createRootStyle.js
packages/app-mobile/utils/debounce.js
packages/app-mobile/utils/fs-driver-rn.js
packages/app-mobile/utils/markupLanguageUtils.js
packages/app-mobile/utils/setupNotifications.js
packages/app-mobile/utils/shareHandler.js
packages/app-mobile/utils/types.js

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

View File

@@ -262,6 +262,8 @@ class Application extends BaseApplication {
if (this.initPluginServiceDone_) return;
this.initPluginServiceDone_ = true;
PlatformImplementation.instance().initialize((action: any) => this.dispatch(action));
const service = PluginService.instance();
const pluginRunner = new PluginRunner();

View File

@@ -5,6 +5,8 @@ import { VersionInfo } from '@joplin/lib/services/plugins/api/types';
import Setting from '@joplin/lib/models/Setting';
import { reg } from '@joplin/lib/registry';
import BasePlatformImplementation, { Joplin } from '@joplin/lib/services/plugins/BasePlatformImplementation';
import { Dispatch } from 'redux';
import { readFile } from 'fs-extra';
const { clipboard, nativeImage } = require('electron');
const packageInfo = require('../../packageInfo');
@@ -20,12 +22,17 @@ export default class PlatformImplementation extends BasePlatformImplementation {
private static instance_: PlatformImplementation;
private joplin_: Joplin;
private components_: Components;
private dispatch_: Dispatch|null = null;
public static instance(): PlatformImplementation {
if (!this.instance_) this.instance_ = new PlatformImplementation();
return this.instance_;
}
public initialize(dispatch: Dispatch) {
this.dispatch_ = dispatch;
}
public get versionInfo(): VersionInfo {
return {
version: packageInfo.version,
@@ -45,6 +52,14 @@ export default class PlatformImplementation extends BasePlatformImplementation {
public get window(): WindowImplementation {
return {
injectCustomStyles: injectCustomStyles,
loadNoteCssFile: async (filePath) => {
const cssString = await readFile(filePath, 'utf8');
this.dispatch_({
type: 'CUSTOM_CSS_APPEND',
css: cssString,
});
},
};
}

View File

@@ -47,7 +47,7 @@ react {
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
//
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"]
hermesFlags = ["-O", "-output-source-map"]
}
/**

View File

@@ -2,7 +2,7 @@ import { useEffect, useState, useMemo, useRef } from 'react';
import shim from '@joplin/lib/shim';
import Setting from '@joplin/lib/models/Setting';
const { themeStyle } = require('../../global-style.js');
import markupLanguageUtils from '@joplin/lib/markupLanguageUtils';
import markupLanguageUtils from '../../../utils/markupLanguageUtils';
import Logger from '@joplin/utils/Logger';
const { assetsToHeaders } = require('@joplin/renderer');

View File

@@ -328,7 +328,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=/usr/local/bin/node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
shellScript = "export NODE_BINARY=/usr/local/bin/node\nexport SOURCEMAP_FILE=\"$(pwd)/../main.jsbundle.map\";\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
};
027E2AA6B101F8CFCA582EC1 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;

View File

@@ -13,15 +13,17 @@
const path = require('path');
const localPackages = {
'@joplin/fork-htmlparser2': path.resolve(__dirname, '../fork-htmlparser2/'),
'@joplin/fork-sax': path.resolve(__dirname, '../fork-sax/'),
'@joplin/fork-uslug': path.resolve(__dirname, '../fork-uslug/'),
'@joplin/lib': path.resolve(__dirname, '../lib/'),
'@joplin/react-native-alarm-notification': path.resolve(__dirname, '../react-native-alarm-notification/'),
'@joplin/react-native-saf-x': path.resolve(__dirname, '../react-native-saf-x/'),
'@joplin/renderer': path.resolve(__dirname, '../renderer/'),
'@joplin/tools': path.resolve(__dirname, '../tools/'),
'@joplin/turndown-plugin-gfm': path.resolve(__dirname, '../turndown-plugin-gfm/'),
'@joplin/turndown': path.resolve(__dirname, '../turndown/'),
'@joplin/utils': path.resolve(__dirname, '../utils/'),
'@joplin/fork-htmlparser2': path.resolve(__dirname, '../fork-htmlparser2/'),
'@joplin/fork-uslug': path.resolve(__dirname, '../fork-uslug/'),
'@joplin/react-native-saf-x': path.resolve(__dirname, '../react-native-saf-x/'),
'@joplin/react-native-alarm-notification': path.resolve(__dirname, '../react-native-alarm-notification/'),
'@joplin/fork-sax': path.resolve(__dirname, '../fork-sax/'),
};
const remappedPackages = {
@@ -32,7 +34,12 @@ const remappedPackages = {
// versions. For example, this allows us to `import {resolve} from 'path'` rather than
// `const { resolve } = require('path-browserify')` ('path-browerify' doesn't have its own type
// definitions).
const browserifiedPackages = ['path'];
const browserifiedPackages = [
'http',
'https',
'os',
'path',
];
for (const package of browserifiedPackages) {
remappedPackages[package] = path.resolve(__dirname, `./node_modules/${package}-browserify/`);
}
@@ -74,6 +81,30 @@ module.exports = {
},
}
),
// Documentation at https://facebook.github.io/metro/docs/configuration/
resolveRequest: (context, moduleName, platform) => {
// console.info('Module: ' + moduleName + ' / ' + context.originModulePath);
// This can be used to allow importing a module that requires `fs`
// somewhere. For example, the `css` package which is used to parse
// CSS strings has a `loadFile()` function that we don't need, but
// that makes it import the `fs` package.
//
// So by having this here, we can use those packages as long as we
// don't use the specific methods that require `fs`. It's something
// to keep in mind if we get weird-related fs errors - it may be
// because the package is trying to access the mocked `fs` package.
if (moduleName === 'fs') {
return {
filePath: path.resolve(__dirname, 'mock-fs.js'),
type: 'sourceFile',
};
}
// Default resolver
return context.resolveRequest(context, moduleName, platform);
},
},
projectRoot: path.resolve(__dirname),
watchFolders: watchedFolders,

View File

@@ -0,0 +1,13 @@
function traceMethodCalls(obj) {
const handler = {
get(_target, propKey, _receiver) {
if (propKey === '$$typeof') return 'object';
throw new Error(`Trying to access member of mocked fs package: \`fs.${propKey}\``);
},
};
return new Proxy(obj, handler);
}
const mockFs = {};
module.exports = traceMethodCalls(mockFs);

View File

@@ -35,9 +35,12 @@
"crypto-browserify": "3.12.0",
"deprecated-react-native-prop-types": "4.0.0",
"events": "3.3.0",
"http-browserify": "1.7.0",
"https-browserify": "1.0.0",
"jsc-android": "241213.1.0",
"lodash": "4.17.21",
"md5": "2.3.0",
"os-browserify": "0.3.0",
"path-browserify": "1.0.1",
"prop-types": "15.8.1",
"punycode": "2.3.0",
@@ -56,7 +59,7 @@
"react-native-fs": "2.20.0",
"react-native-gesture-handler": "2.12.0",
"react-native-get-random-values": "1.9.0",
"react-native-image-picker": "5.4.2",
"react-native-image-picker": "5.6.0",
"react-native-image-resizer": "1.4.5",
"react-native-localize": "3.0.2",
"react-native-modal-datetime-picker": "15.0.1",
@@ -65,7 +68,7 @@
"react-native-quick-actions": "0.3.13",
"react-native-reanimated": "3.3.0",
"react-native-rsa-native": "2.0.5",
"react-native-safe-area-context": "4.5.5",
"react-native-safe-area-context": "4.6.0",
"react-native-securerandom": "1.0.1",
"react-native-share": "8.2.2",
"react-native-sqlite-storage": "6.0.1",

View File

@@ -0,0 +1,7 @@
const initPlugin = joplin => {
!function(t){var e={};function o(n){if(e[n])return e[n].exports;var r=e[n]={i:n,l:!1,exports:{}};return t[n].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.m=t,o.c=e,o.d=function(t,e,n){o.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},o.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)o.d(n,r,function(e){return t[e]}.bind(null,r));return n},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,"a",e),e},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o.p="",o(o.s=0)}([function(t,e,o){"use strict";var n=this&&this.__awaiter||function(t,e,o,n){return new(o||(o=Promise))((function(r,i){function u(t){try{c(n.next(t))}catch(t){i(t)}}function l(t){try{c(n.throw(t))}catch(t){i(t)}}function c(t){var e;t.done?r(t.value):(e=t.value,e instanceof o?e:new o((function(t){t(e)}))).then(u,l)}c((n=n.apply(t,e||[])).next())}))};Object.defineProperty(e,"__esModule",{value:!0});const r=o(1),i=o(2);r.default.plugins.register({onStart:function(){return n(this,void 0,void 0,(function*(){yield r.default.contentScripts.register(i.ContentScriptType.MarkdownItPlugin,"todoTxtMd","./todoTxtMdRule.js"),yield r.default.contentScripts.register(i.ContentScriptType.CodeMirrorPlugin,"todoTxtMdCtrl","./todoTxtMdCtrl.js"),yield r.default.contentScripts.onMessage("todoTxtMd",t=>{r.default.commands.execute("editor.execCommand",{name:"todoTxtAction",args:[t]}),r.default.commands.execute("editor.focus")})}))}})},function(t,e,o){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=joplin},function(t,e,o){"use strict";var n;Object.defineProperty(e,"__esModule",{value:!0}),e.ContentScriptType=e.SettingStorage=e.AppType=e.SettingItemType=e.ToolbarButtonLocation=e.isContextMenuItemLocation=e.MenuItemLocation=e.ImportModuleOutputFormat=e.FileSystemItem=void 0,function(t){t.File="file",t.Directory="directory"}(e.FileSystemItem||(e.FileSystemItem={})),function(t){t.Markdown="md",t.Html="html"}(e.ImportModuleOutputFormat||(e.ImportModuleOutputFormat={})),function(t){t.File="file",t.Edit="edit",t.View="view",t.Note="note",t.Tools="tools",t.Help="help",t.Context="context",t.NoteListContextMenu="noteListContextMenu",t.EditorContextMenu="editorContextMenu",t.FolderContextMenu="folderContextMenu",t.TagContextMenu="tagContextMenu"}(n=e.MenuItemLocation||(e.MenuItemLocation={})),e.isContextMenuItemLocation=function(t){return[n.Context,n.NoteListContextMenu,n.EditorContextMenu,n.FolderContextMenu,n.TagContextMenu].includes(t)},function(t){t.NoteToolbar="noteToolbar",t.EditorToolbar="editorToolbar"}(e.ToolbarButtonLocation||(e.ToolbarButtonLocation={})),function(t){t[t.Int=1]="Int",t[t.String=2]="String",t[t.Bool=3]="Bool",t[t.Array=4]="Array",t[t.Object=5]="Object",t[t.Button=6]="Button"}(e.SettingItemType||(e.SettingItemType={})),function(t){t.Desktop="desktop",t.Mobile="mobile",t.Cli="cli"}(e.AppType||(e.AppType={})),function(t){t[t.Database=1]="Database",t[t.File=2]="File"}(e.SettingStorage||(e.SettingStorage={})),function(t){t.MarkdownItPlugin="markdownItPlugin",t.CodeMirrorPlugin="codeMirrorPlugin"}(e.ContentScriptType||(e.ContentScriptType={}))}]);
}
module.exports = { initPlugin };

View File

@@ -0,0 +1,12 @@
{
"manifest_version": 1,
"id": "com.hieuthi.joplin.metis",
"app_min_version": "2.2",
"version": "0.1.5",
"name": "Metis",
"description": "A Simple Task Manager Plugin for Joplin based on Todo.txt Specification",
"author": "Hieu-Thi Luong",
"homepage_url": "https://github.com/hieuthi/joplin-plugin-metis",
"repository_url": "https://github.com/hieuthi/joplin-plugin-metis",
"keywords": ["joplin-plugin","todo","todotxt","task management"]
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,163 @@
ul.todotxt {
--color-default: #999;
--color-faded: #999;
--color-A: rgb(247, 210, 110); /* yellow* */
--color-B: rgb(152, 104, 1); /* red */
--color-C: rgb(80, 161, 79); /* green */
--color-D: rgb(21, 91, 218); /* blue */
--project-background-color: rgb(247, 210, 110);
--project-color: black;
--context-color: rgb(152, 104, 1);
--transition-duration: 0.15s;
}
ul.todotxt { list-style:none; }
ul.todotxt li {
list-style-type:none;
border-bottom: dashed 1px;
margin-bottom: 4px;
line-height: 1.2em;
}
ul.todotxt li.todotxt-header {
font-size: 10px;
}
.todo-priority {
display: inline-block;
width: 1.2em;
overflow: hidden;
color: var(--color-default);
vertical-align: text-bottom;
}
.todo-priority select {
appearance: none;
background-color: transparent;
border-color: transparent;
color: inherit;
font-size: inherit;
font-weight: 700;
cursor: pointer;
}
.todo-priority select:focus-visible {
outline: none;
}
.todo-priority select:hover {
text-decoration: underline;
}
.todo-panel {
display: block;
font-size: 12px;
line-height: 1em;
text-align: right;
margin: 2px 0 4px 0;
color: var(--color-faded);
}
.todo-completion, .todo-creation {
display: inline-block;
min-width: 6em;
}
.todo-project {
background-color: var(--project-background-color);
color: var(--project-color);
border-radius: 2px;
}
.todo-context {
color: var(--context-color);
}
.todo-count {
color: var(--color-faded);
}
.todo-count::before{
content: '/';
}
.todo-meta {
color: var(--color-faded);
}
.todo-select {
display: inline-block;
min-width: 3em;
text-decoration: none;
}
.todo-checkbox {
margin-left: -1.9em;
margin-right: 0.5em;
display: inline-block;
vertical-align: text-top;
position: relative;
cursor: pointer;
user-select: none;
}
.todo-checkbox input {
position: absolute;
display: none;
}
.todo-checkbox .todo-checkmark {
width : 1.2em;
height: 1.2em;
position: relative;
display : inline-block;
overflow: hidden;
text-align: center;
color: white;
border: solid 1px var(--color-default);
border-radius: 100%;
transition: background-color var(--transition-duration) ease-in;
}
.todo-checkbox input:checked ~ .todo-checkmark {
background-color: var(--color-default);
}
.todo-checkbox .todo-checkmark:after {
content: '×';
position: relative;
display: inline-block;
transition: opacity var(--transition-duration);
opacity: 0;
}
.todo-checkbox input:checked ~ .todo-checkmark:after {
opacity: 1.0;
}
/* Color scheme */
.prior-A .todo-priority {
color: var(--color-A);
}
.prior-A .todo-checkbox .todo-checkmark {
border-color: var(--color-A);
color: black;
}
.prior-A .todo-checkbox input:checked ~ .todo-checkmark {
background-color: var(--color-A);
}
.prior-B .todo-priority {
color: var(--color-B);
}
.prior-B .todo-checkbox .todo-checkmark {
border-color: var(--color-B);
}
.prior-B .todo-checkbox input:checked ~ .todo-checkmark {
background-color: var(--color-B);
}
.prior-C .todo-priority {
color: var(--color-C);
}
.prior-C .todo-checkbox .todo-checkmark {
border-color: var(--color-C);
}
.prior-C .todo-checkbox input:checked ~ .todo-checkmark {
background-color: var(--color-C);
}
.prior-D .todo-priority {
color: var(--color-D);
}
.prior-D .todo-checkbox .todo-checkmark {
border-color: var(--color-D);
}
.prior-D .todo-checkbox input:checked ~ .todo-checkmark {
background-color: var(--color-D);
}

View File

@@ -0,0 +1,38 @@
document.addEventListener('joplin-noteDidUpdate', makeTodoViewActionable );
if (/WebKit/i.test(navigator.userAgent)) { // sniff
var _timer_todotxt = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
makeTodoViewActionable()
}
}, 10);
}
function makeTodoViewActionable() {
if (_timer_todotxt) clearInterval(_timer_todotxt);
const todoTxts = document.getElementsByClassName('todotxt');
for (var i=0; i<todoTxts.length; i++){
const todoTxt = todoTxts[i];
const todos = todoTxt.getElementsByClassName('todo');
for (var j=0; j<todos.length; j++){
const todo = todos[j];
const lineIdx = todo.getAttribute("data-lineIdx");
const checkbox = todo.getElementsByClassName('todo-checkbox')[0].getElementsByTagName('input')[0];
const priority = todo.getElementsByClassName('todo-priority')[0].getElementsByTagName('select')[0];
const selectButton = todo.getElementsByClassName('todo-select')[0];
checkbox.onclick = function (){
setTimeout(()=> {webviewApi.postMessage('todoTxtMd', `toggleStatus:${lineIdx}`)}, 170);
}
priority.onchange = function(option) {
var value = option.target.value;
webviewApi.postMessage('todoTxtMd', `changePriority:${lineIdx}:${value}`);
}
selectButton.onclick = function () {
webviewApi.postMessage('todoTxtMd', `selectLine:${lineIdx}`);
}
}
}
}

View File

@@ -0,0 +1,17 @@
const initPlugin = joplin => {
joplin.plugins.register({
onStart: async function() {
await joplin.contentScripts.register(
'markdownItPlugin',
'abc_music_sheet',
'./markdownItPlugin.js'
);
},
});
//!function(t){var e={};function n(o){if(e[o])return e[o].exports;var r=e[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=t,n.c=e,n.d=function(t,e,o){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:o})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)n.d(o,r,function(e){return t[e]}.bind(null,r));return o},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=0)}([function(t,e,n){"use strict";var o=this&&this.__awaiter||function(t,e,n,o){return new(n||(n=Promise))((function(r,i){function u(t){try{c(o.next(t))}catch(t){i(t)}}function l(t){try{c(o.throw(t))}catch(t){i(t)}}function c(t){var e;t.done?r(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(u,l)}c((o=o.apply(t,e||[])).next())}))};Object.defineProperty(e,"__esModule",{value:!0});const r=n(1),i=n(2);r.default.plugins.register({onStart:function(){return o(this,void 0,void 0,(function*(){yield r.default.contentScripts.register(i.ContentScriptType.MarkdownItPlugin,"abc_music_sheet","./markdownItPlugin.js"),setInterval(()=>{console.log("AAAAAAAAAAAAAAA")},1e3)}))}})},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default=joplin},function(t,e,n){"use strict";var o;Object.defineProperty(e,"__esModule",{value:!0}),e.ContentScriptType=e.SettingStorage=e.AppType=e.SettingItemType=e.ToolbarButtonLocation=e.isContextMenuItemLocation=e.MenuItemLocation=e.ImportModuleOutputFormat=e.FileSystemItem=void 0,function(t){t.File="file",t.Directory="directory"}(e.FileSystemItem||(e.FileSystemItem={})),function(t){t.Markdown="md",t.Html="html"}(e.ImportModuleOutputFormat||(e.ImportModuleOutputFormat={})),function(t){t.File="file",t.Edit="edit",t.View="view",t.Note="note",t.Tools="tools",t.Help="help",t.Context="context",t.NoteListContextMenu="noteListContextMenu",t.EditorContextMenu="editorContextMenu",t.FolderContextMenu="folderContextMenu",t.TagContextMenu="tagContextMenu"}(o=e.MenuItemLocation||(e.MenuItemLocation={})),e.isContextMenuItemLocation=function(t){return[o.Context,o.NoteListContextMenu,o.EditorContextMenu,o.FolderContextMenu,o.TagContextMenu].includes(t)},function(t){t.NoteToolbar="noteToolbar",t.EditorToolbar="editorToolbar"}(e.ToolbarButtonLocation||(e.ToolbarButtonLocation={})),function(t){t[t.Int=1]="Int",t[t.String=2]="String",t[t.Bool=3]="Bool",t[t.Array=4]="Array",t[t.Object=5]="Object",t[t.Button=6]="Button"}(e.SettingItemType||(e.SettingItemType={})),function(t){t.Desktop="desktop",t.Mobile="mobile",t.Cli="cli"}(e.AppType||(e.AppType={})),function(t){t[t.Database=1]="Database",t[t.File=2]="File"}(e.SettingStorage||(e.SettingStorage={})),function(t){t.MarkdownItPlugin="markdownItPlugin",t.CodeMirrorPlugin="codeMirrorPlugin"}(e.ContentScriptType||(e.ContentScriptType={}))}]);
}
module.exports = { initPlugin };

View File

@@ -0,0 +1,16 @@
{
"manifest_version": 1,
"id": "org.joplinapp.plugins.AbcSheetMusic",
"app_min_version": "2.2",
"version": "1.0.2",
"name": "ABC Sheet Music Plugin",
"description": "Turns ABC text notation into sheet music",
"author": "Laurent Cozic",
"homepage_url": "https://github.com/joplin/plugin-abc-sheet-music",
"repository_url": "https://github.com/joplin/plugin-abc-sheet-music",
"keywords": [
"sheet music",
"abc",
"notation"
]
}

View File

@@ -0,0 +1,14 @@
const initPlugin = joplin => {
joplin.plugins.register({
onStart: async function() {
// eslint-disable-next-line no-console
console.info('RUNNING AS PLUGIN 1: ', await joplin.plugins.id()); // await joplin.plugins.id());
// const folder = await joplin.data.post(['folders'], null, { title: "my plugin folder" });
// await joplin.data.post(['notes'], null, { parent_id: folder.id, title: "testing plugin!" });
},
});
}
module.exports = { initPlugin };

View File

@@ -0,0 +1,12 @@
{
"id": "org.joplinapp.plugins.Simple",
"manifest_version": 1,
"app_min_version": "1.4",
"name": "Joplin Simple Plugin",
"version": "1.0.0",
"description": "To test loading and running a plugin",
"homepage_url": "https://joplinapp.org",
"permissions": [
"model"
]
}

View File

@@ -0,0 +1,14 @@
const initPlugin = joplin => {
joplin.plugins.register({
onStart: async function() {
// eslint-disable-next-line no-console
console.info('RUNNING AS PLUGIN 2: ', await joplin.plugins.id());
// const folder = await joplin.data.post(['folders'], null, { title: "my plugin folder" });
// await joplin.data.post(['notes'], null, { parent_id: folder.id, title: "testing plugin!" });
},
});
}
module.exports = { initPlugin };

View File

@@ -0,0 +1,12 @@
{
"id": "org.joplinapp.plugins.Simple2",
"manifest_version": 1,
"app_min_version": "1.4",
"name": "Joplin Simple Plugin",
"version": "1.0.0",
"description": "To test loading and running a plugin",
"homepage_url": "https://joplinapp.org",
"permissions": [
"model"
]
}

View File

@@ -85,6 +85,7 @@ const SyncTargetWebDAV = require('@joplin/lib/SyncTargetWebDAV.js');
const SyncTargetDropbox = require('@joplin/lib/SyncTargetDropbox.js');
const SyncTargetAmazonS3 = require('@joplin/lib/SyncTargetAmazonS3.js');
import BiometricPopup from './components/biometrics/BiometricPopup';
import PluginService from '@joplin/lib/services/plugins/PluginService';
SyncTargetRegistry.addClass(SyncTargetNone);
SyncTargetRegistry.addClass(SyncTargetOneDrive);
@@ -120,6 +121,7 @@ import { ReactNode } from 'react';
import userFetcher, { initializeUserFetcher } from '@joplin/lib/utils/userFetcher';
import { parseShareCache } from '@joplin/lib/services/share/reducer';
import autodetectTheme, { onSystemColorSchemeChange } from './utils/autodetectTheme';
import PluginRunner from './services/plugins/PluginRunner';
type SideMenuPosition = 'left' | 'right';
@@ -438,6 +440,97 @@ const initializeTempDir = async () => {
return tempDir;
};
const simplePlugin1 = require('./plugins/org.joplinapp.plugins.Simple/index.js');
const simplePluginManifest1 = `{
"id": "org.joplinapp.plugins.Simple",
"manifest_version": 1,
"app_min_version": "1.4",
"name": "Joplin Simple Plugin",
"version": "1.0.0",
"description": "To test loading and running a plugin",
"homepage_url": "https://joplinapp.org",
"permissions": [
"model"
]
}`;
const simplePlugin2 = require('./plugins/org.joplinapp.plugins.Simple2/index.js');
const simplePluginManifest2 = `{
"id": "org.joplinapp.plugins.Simple2",
"manifest_version": 1,
"app_min_version": "1.4",
"name": "Joplin Simple Plugin",
"version": "1.0.0",
"description": "To test loading and running a plugin",
"homepage_url": "https://joplinapp.org",
"permissions": [
"model"
]
}`;
// const abcPlugin = require('./plugins/org.joplinapp.plugins.AbcSheetMusic/index.js');
// const abcPluginManifest = `{
// "manifest_version": 1,
// "id": "org.joplinapp.plugins.AbcSheetMusic",
// "app_min_version": "2.2",
// "version": "1.0.2",
// "name": "ABC Sheet Music Plugin",
// "description": "Turns ABC text notation into sheet music",
// "author": "Laurent Cozic",
// "homepage_url": "https://github.com/joplin/plugin-abc-sheet-music",
// "repository_url": "https://github.com/joplin/plugin-abc-sheet-music",
// "keywords": [
// "sheet music",
// "abc",
// "notation"
// ]
// }`;
// const abcPluginContentScript = require('./plugins/org.joplinapp.plugins.AbcSheetMusic/markdownItPlugin.js');
const metisPlugin = require('./plugins/com.hieuthi.joplin.metis/index.js');
const metisManifest = `{
"manifest_version": 1,
"id": "com.hieuthi.joplin.metis",
"app_min_version": "2.2",
"version": "0.1.5",
"name": "Metis",
"description": "A Simple Task Manager Plugin for Joplin based on Todo.txt Specification",
"author": "Hieu-Thi Luong",
"homepage_url": "https://github.com/hieuthi/joplin-plugin-metis",
"repository_url": "https://github.com/hieuthi/joplin-plugin-metis",
"keywords": ["joplin-plugin","todo","todotxt","task management"]
}`;
const metisContentScript = require('./plugins/com.hieuthi.joplin.metis/todoTxtMdRule.js');
const initPluginService = async () => {
const service = PluginService.instance();
const runner = new PluginRunner();
service.initialize(
'2.12.1',
{
joplin: {},
},
runner,
{
dispatch: () => {},
getState: () => {},
}
);
const plugin1 = await PluginService.instance().loadPluginFromModule({ main: simplePlugin1 }, simplePluginManifest1);
await PluginService.instance().runPlugin(plugin1);
const plugin2 = await PluginService.instance().loadPluginFromModule({ main: simplePlugin2 }, simplePluginManifest2);
await PluginService.instance().runPlugin(plugin2);
// const plugin3 = await PluginService.instance().loadPluginFromModule({ main: abcPlugin, contentScripts: { ['markdownItPlugin.js']: abcPluginContentScript } }, abcPluginManifest);
// await PluginService.instance().runPlugin(plugin3);
const plugin4 = await PluginService.instance().loadPluginFromModule({ main: metisPlugin, contentScripts: { ['todoTxtMdView.js']: metisContentScript } }, metisManifest);
await PluginService.instance().runPlugin(plugin4);
};
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
async function initialize(dispatch: Function) {
shimInit();
@@ -705,6 +798,8 @@ async function initialize(dispatch: Function) {
// and it cannot collect anything when the app is not active.
RevisionService.instance().runInBackground(1000 * 30);
await initPluginService();
// ----------------------------------------------------------------------------
// Keep this below to test react-native-rsa-native
// ----------------------------------------------------------------------------

View File

@@ -0,0 +1,15 @@
import Global from '@joplin/lib/services/plugins/api/Global';
import BasePluginRunner from '@joplin/lib/services/plugins/BasePluginRunner';
import Plugin from '@joplin/lib/services/plugins/Plugin';
import Logger from '@joplin/utils/Logger';
const logger = Logger.create('PluginRunner');
export default class PluginRunner extends BasePluginRunner {
public async run(plugin: Plugin, sandbox: Global): Promise<void> {
logger.info(`Run plugin: ${plugin.id}`);
plugin.module.main.initPlugin(sandbox.joplin);
}
}

View File

@@ -256,12 +256,8 @@ export default class FsDriverRN extends FsDriverBase {
return output ? output : null;
}
public resolve(path: string) {
throw new Error(`Not implemented: resolve(): ${path}`);
}
public resolveRelativePathWithinDir(_baseDir: string, relativePath: string) {
throw new Error(`Not implemented: resolveRelativePathWithinDir(): ${relativePath}`);
public resolve(...pathSegments: string[]) {
return resolve(...pathSegments);
}
public async md5File(path: string): Promise<string> {

View File

@@ -0,0 +1,21 @@
import { MarkupLanguageUtils as BaseMarkupLanguageUtils } from '@joplin/lib/markupLanguageUtils';
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
import { contentScriptsToRendererRules } from '@joplin/lib/services/plugins/utils/loadContentScripts';
import { Options } from '@joplin/renderer/MarkupToHtml';
class MarkupLanguageUtils extends BaseMarkupLanguageUtils {
public newMarkupToHtml(plugins: PluginStates = null, options: Options = null) {
plugins = plugins || {};
return super.newMarkupToHtml(null, {
extraRendererRules: contentScriptsToRendererRules(plugins),
...options,
});
}
}
const markupLanguageUtils = new MarkupLanguageUtils();
export default markupLanguageUtils;

View File

@@ -158,6 +158,20 @@ export default class FsDriverBase {
};
}
public resolve(..._pathSegments: string[]): string {
throw new Error('Not implemented');
}
// Resolves the provided relative path to an absolute path within baseDir. The function
// also checks that the absolute path is within baseDir, to avoid security issues.
// It is expected that baseDir is a safe path (not user-provided).
public resolveRelativePathWithinDir(baseDir: string, relativePath: string) {
const resolvedBaseDir = this.resolve(baseDir);
const resolvedPath = this.resolve(baseDir, relativePath);
if (resolvedPath.indexOf(resolvedBaseDir) !== 0) throw new Error(`Resolved path for relative path "${relativePath}" is not within base directory "${baseDir}" (Was resolved to ${resolvedPath})`);
return resolvedPath;
}
public async tarExtract(_options: any) {
throw new Error('Not implemented');
}

View File

@@ -186,18 +186,8 @@ export default class FsDriverNode extends FsDriverBase {
throw new Error(`Unsupported encoding: ${encoding}`);
}
public resolve(path: string) {
return require('path').resolve(path);
}
// Resolves the provided relative path to an absolute path within baseDir. The function
// also checks that the absolute path is within baseDir, to avoid security issues.
// It is expected that baseDir is a safe path (not user-provided).
public resolveRelativePathWithinDir(baseDir: string, relativePath: string) {
const resolvedBaseDir = nodeResolve(baseDir);
const resolvedPath = nodeResolve(baseDir, relativePath);
if (resolvedPath.indexOf(resolvedBaseDir) !== 0) throw new Error(`Resolved path for relative path "${relativePath}" is not within base directory "${baseDir}" (Was resolved to ${resolvedPath})`);
return resolvedPath;
public resolve(...pathSegments: string[]) {
return nodeResolve(...pathSegments);
}
public async md5File(path: string): Promise<string> {

View File

@@ -4,6 +4,7 @@ import shim from '../../shim';
import { ViewHandle } from './utils/createViewHandle';
import { ContentScriptType } from './api/types';
import Logger from '@joplin/utils/Logger';
import Joplin from './api/Joplin';
const EventEmitter = require('events');
const logger = Logger.create('Plugin');
@@ -15,12 +16,20 @@ interface ViewControllers {
export interface ContentScript {
id: string;
path: string;
module?: any;
}
interface ContentScripts {
[type: string]: ContentScript[];
}
export interface Module {
main: {
initPlugin: (joplin: Joplin)=> void;
};
contentScripts?: Record<string, any>;
}
export default class Plugin {
private baseDir_: string;
@@ -38,14 +47,16 @@ export default class Plugin {
private contentScriptMessageListeners_: Record<string, Function> = {};
private dataDir_: string;
private dataDirCreated_ = false;
private module_: Module|null = null;
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
public constructor(baseDir: string, manifest: PluginManifest, scriptText: string, dispatch: Function, dataDir: string) {
this.baseDir_ = shim.fsDriver().resolve(baseDir);
public constructor(baseDir: string, manifest: PluginManifest, scriptText: string, dispatch: Function, dataDir: string, module: Module|null = null) {
this.baseDir_ = baseDir ? shim.fsDriver().resolve(baseDir) : '';
this.manifest_ = manifest;
this.scriptText_ = scriptText;
this.dispatch_ = dispatch;
this.dataDir_ = dataDir;
this.module_ = module;
this.eventEmitter_ = new EventEmitter();
}
@@ -73,6 +84,10 @@ export default class Plugin {
return this.baseDir_;
}
public get module(): Module|null {
return this.module_;
}
public async dataDir(): Promise<string> {
if (this.dataDirCreated_) return this.dataDir_;
@@ -105,13 +120,25 @@ export default class Plugin {
public async registerContentScript(type: ContentScriptType, id: string, path: string) {
if (!this.contentScripts_[type]) this.contentScripts_[type] = [];
const absolutePath = shim.fsDriver().resolveRelativePathWithinDir(this.baseDir, path);
let absolutePath = '';
let scriptModule: any = null;
if (!(await shim.fsDriver().exists(absolutePath))) throw new Error(`Could not find content script at path ${absolutePath}`);
if (this.module) {
const normalizePath = (p: string) => {
if (p.startsWith('./')) return p.substring(2);
return p;
};
this.contentScripts_[type].push({ id, path: absolutePath });
const moduleKey = normalizePath(path);
scriptModule = this.module.contentScripts[moduleKey];
logger.debug(`"${this.id}": Registered content script: ${type}: ${id}: ${moduleKey}`);
} else {
absolutePath = shim.fsDriver().resolveRelativePathWithinDir(this.baseDir, path);
if (!(await shim.fsDriver().exists(absolutePath))) throw new Error(`Could not find content script at path ${absolutePath}`);
logger.debug(`"${this.id}": Registered content script: ${type}: ${id}: ${absolutePath}`);
}
logger.debug(`"${this.id}": Registered content script: ${type}: ${id}: ${absolutePath}`);
this.contentScripts_[type].push({ id, path: absolutePath, module: scriptModule });
this.dispatch_({
type: 'PLUGIN_CONTENT_SCRIPTS_ADD',
@@ -120,6 +147,7 @@ export default class Plugin {
type: type,
id: id,
path: absolutePath,
module: scriptModule,
},
});
}

View File

@@ -1,4 +1,4 @@
import Plugin from './Plugin';
import Plugin, { Module } from './Plugin';
import manifestFromObject from './utils/manifestFromObject';
import Global from './api/Global';
import BasePluginRunner from './BasePluginRunner';
@@ -28,6 +28,10 @@ export interface Plugins {
[key: string]: Plugin;
}
export interface PluginModule {
}
export interface SettingAndValue {
[settingName: string]: string;
}
@@ -283,7 +287,17 @@ export default class PluginService extends BaseService {
}
}
private async loadPlugin(baseDir: string, manifestText: string, scriptText: string, pluginIdIfNotSpecified: string): Promise<Plugin> {
public async loadPluginFromModule(module: Module, manifestText: string): Promise<Plugin> {
return this.loadPlugin(
'',
manifestText,
'',
'',
module
);
}
private async loadPlugin(baseDir: string, manifestText: string, scriptText: string, pluginIdIfNotSpecified: string, module: Module|null = null): Promise<Plugin> {
baseDir = rtrimSlashes(baseDir);
const manifestObj = JSON.parse(manifestText);
@@ -318,7 +332,7 @@ export default class PluginService extends BaseService {
const dataDir = `${Setting.value('pluginDataDir')}/${manifest.id}`;
const plugin = new Plugin(baseDir, manifest, scriptText, (action: any) => this.store_.dispatch(action), dataDir);
const plugin = new Plugin(baseDir, manifest, scriptText, (action: any) => this.store_.dispatch(action), dataDir, module);
for (const notice of deprecationNotices) {
plugin.deprecationNotice(notice.goneInVersion, notice.message, notice.isError);

View File

@@ -71,6 +71,10 @@ export default class JoplinPlugins {
return this.plugin.dataDir();
}
public async id(): Promise<string> {
return this.plugin.id;
}
/**
* Gets the plugin installation directory. This can be used to access any
* asset that was packaged with the plugin. This directory should be

View File

@@ -1,22 +1,20 @@
/* eslint-disable multiline-comment-style */
import Plugin from '../Plugin';
import * as fs from 'fs-extra';
export interface Implementation {
injectCustomStyles(elementId: string, cssFilePath: string): Promise<void>;
loadNoteCssFile(filePath: string): Promise<void>;
}
export default class JoplinWindow {
private plugin_: Plugin;
private store_: any;
private implementation_: Implementation;
public constructor(implementation: Implementation, plugin: Plugin, store: any) {
public constructor(implementation: Implementation, plugin: Plugin, _store: any) {
this.implementation_ = implementation;
this.plugin_ = plugin;
this.store_ = store;
}
/**
@@ -36,12 +34,7 @@ export default class JoplinWindow {
* for an example.
*/
public async loadNoteCssFile(filePath: string) {
const cssString = await fs.readFile(filePath, 'utf8');
this.store_.dispatch({
type: 'CUSTOM_CSS_APPEND',
css: cssString,
});
await this.implementation_.loadNoteCssFile(filePath);
}
}

View File

@@ -17,6 +17,7 @@ interface PluginViewStates {
interface PluginContentScriptState {
id: string;
path: string;
module?: any;
}
interface PluginContentScriptStates {
@@ -170,6 +171,7 @@ const reducer = (draftRoot: Draft<any>, action: any) => {
draft.plugins[action.pluginId].contentScripts[type].push({
id: action.contentScript.id,
path: action.contentScript.path,
module: action.contentScript.module,
});
break;
}

View File

@@ -27,6 +27,7 @@ const { fileExtension, safeFileExtension, safeFilename, filename } = require('..
const { fileUriToPath } = require('../../../urlUtils');
const { MarkupToHtml } = require('@joplin/renderer');
const { ErrorNotFound } = require('../utils/errors');
const minify = require('html-minifier').minify;
const logger = Logger.create('routes/notes');
@@ -51,7 +52,6 @@ async function requestNoteToNote(requestNote: any) {
if (requestNote.body_html) {
if (requestNote.convert_to === 'html') {
const style = await buildNoteStyleSheet(requestNote.stylesheets);
const minify = require('html-minifier').minify;
const minifyOptions = {
// Remove all spaces and, especially, newlines from tag attributes, as that would

View File

@@ -7,6 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Joplin-CLI 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: genneko <genneko217@gmail.com>\n"
"Language-Team: \n"
"Language: ja_JP\n"
@@ -14,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Poedit 3.0.1\n"
"X-Generator: Poedit 3.3.2\n"
#: packages/app-mobile/components/screens/ConfigScreen.tsx:687
msgid "- Camera: to allow taking a picture and attaching it to a note."
@@ -91,7 +93,7 @@ msgstr "%d 日"
#: packages/lib/utils/joplinCloud.ts:136 packages/lib/utils/joplinCloud.ts:137
#: packages/lib/utils/joplinCloud.ts:138
msgid "%d GB"
msgstr ""
msgstr "%d GB"
#: packages/lib/utils/joplinCloud.ts:133 packages/lib/utils/joplinCloud.ts:134
#: packages/lib/utils/joplinCloud.ts:135
@@ -109,7 +111,7 @@ msgstr "%d 時間"
#: packages/lib/utils/joplinCloud.ts:124 packages/lib/utils/joplinCloud.ts:125
#: packages/lib/utils/joplinCloud.ts:126
msgid "%d MB"
msgstr ""
msgstr "%d MB"
#: packages/lib/utils/joplinCloud.ts:121 packages/lib/utils/joplinCloud.ts:122
#: packages/lib/utils/joplinCloud.ts:123
@@ -322,7 +324,7 @@ msgstr "高度なツール"
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:98
msgid ""
"All data, including notes, notebooks and tags will be permanently deleted."
msgstr ""
msgstr "ノート、ノートブック、タグを含むすべてのデータが完全に削除されます。"
#: packages/app-desktop/gui/Sidebar/Sidebar.tsx:495
#: packages/app-mobile/components/screens/Notes.tsx:174
@@ -394,9 +396,8 @@ msgid "Aritim Dark"
msgstr "Aritim Dark"
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:206
#, fuzzy
msgid "Attach"
msgstr "添付..."
msgstr "添付"
#: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:53
#: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:594
@@ -1243,9 +1244,8 @@ msgstr ""
"できなくなります。"
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:97
#, fuzzy
msgid "Delete this profile?"
msgstr "これら %d のノートを削除しますか?"
msgstr "このプロファイルを削除しますか?"
#: packages/lib/Synchronizer.ts:186
msgid "Deleted local items: %d."
@@ -1482,9 +1482,8 @@ msgid "Edit in external editor"
msgstr "外部エディターで編集"
#: packages/app-mobile/components/NoteEditor/EditLinkDialog.tsx:141
#, fuzzy
msgid "Edit link"
msgstr "ノートブックの編集"
msgstr "リンクの編集"
#: packages/app-cli/app/command-edit.js:17
msgid "Edit note."
@@ -1496,9 +1495,8 @@ msgid "Edit notebook"
msgstr "ノートブックの編集"
#: packages/app-mobile/components/ProfileSwitcher/ProfileEditor.tsx:87
#, fuzzy
msgid "Edit profile"
msgstr "プロファイルをエクスポート"
msgstr "プロファイルを編集"
#: packages/app-desktop/commands/editProfileConfig.ts:9
msgid "Edit profile configuration..."
@@ -1643,7 +1641,7 @@ msgstr "ソフトブレークを有効にする"
#: packages/lib/models/Setting.ts:1050
msgid "Enable spellcheck in the text editor"
msgstr ""
msgstr "テキストエディタでスペルチェックを有効にする"
#: packages/lib/models/Setting.ts:1156
msgid "Enable table of contents extension"
@@ -2052,9 +2050,8 @@ msgid "Hide Joplin"
msgstr "Joplinを隠す"
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:253
#, fuzzy
msgid "Hide keyboard"
msgstr "メタデータを隠す"
msgstr "キーボードを隠す"
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/ToggleOverflowButton.tsx:22
#, fuzzy
@@ -2245,9 +2242,8 @@ msgstr "ハイパーリンクの挿入"
#: packages/app-desktop/gui/NoteEditor/editorCommandDeclarations.ts:83
#: packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.tsx:628
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:188
#, fuzzy
msgid "Insert time"
msgstr "日付の入力"
msgstr "日時の挿入"
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginBox.tsx:191
msgid "Install"
@@ -2397,7 +2393,7 @@ msgstr ""
#: packages/app-mobile/components/NoteEditor/MarkdownToolbar/MarkdownToolbar.tsx:162
msgid "KaTeX"
msgstr ""
msgstr "KaTeX"
#: packages/lib/models/Setting.ts:1543
msgid "Keep note history for"
@@ -2576,9 +2572,8 @@ msgid "Manage multiple users"
msgstr "マスターパスワードの管理"
#: packages/app-mobile/components/screens/ConfigScreen.tsx:641
#, fuzzy
msgid "Manage profiles"
msgstr "プロファイルの更新"
msgstr "プロファイルの管理"
#: packages/app-desktop/gui/ConfigScreen/controls/plugins/PluginsStates.tsx:320
msgid "Manage your plugins"
@@ -3039,9 +3034,8 @@ msgid "Open %s"
msgstr "%s を開く"
#: packages/app-desktop/gui/MainScreen/commands/openPdfViewer.ts:7
#, fuzzy
msgid "Open PDF viewer"
msgstr "PDFビューアーを有効にする"
msgstr "PDFビューアーを開く"
#: packages/app-desktop/commands/openProfileDirectory.ts:8
msgid "Open profile directory"
@@ -3120,7 +3114,7 @@ msgstr "貼り付け"
#: packages/app-desktop/gui/NoteEditor/commands/pasteAsText.ts:6
#: packages/app-desktop/gui/NoteEditor/utils/contextMenu.ts:181
msgid "Paste as text"
msgstr ""
msgstr "テキストとして貼り付け"
#: packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx:525
msgid "Path:"
@@ -3325,9 +3319,8 @@ msgid "Profile"
msgstr "プロファイル"
#: packages/app-mobile/components/ProfileSwitcher/ProfileEditor.tsx:95
#, fuzzy
msgid "Profile name"
msgstr "プロファイル名:"
msgstr "プロファイル名"
#: packages/app-desktop/gui/MainScreen/commands/addProfile.ts:17
msgid "Profile name:"
@@ -3338,7 +3331,6 @@ msgid "Profile Version: %s"
msgstr "プロファイルバージョン: %s"
#: packages/app-mobile/components/ProfileSwitcher/ProfileSwitcher.tsx:155
#, fuzzy
msgid "Profiles"
msgstr "プロファイル"
@@ -3431,9 +3423,8 @@ msgid "Refresh"
msgstr "更新"
#: packages/app-mobile/components/NoteEditor/SearchPanel.tsx:313
#, fuzzy
msgid "Regular expression"
msgstr "数式表現を有効にする"
msgstr "正規表現"
#: packages/app-desktop/gui/MainScreen/MainScreen.tsx:629
#: packages/app-desktop/gui/Root.tsx:179
@@ -3491,9 +3482,8 @@ msgid "Replace: "
msgstr ""
#: packages/app-desktop/gui/MainScreen/commands/resetLayout.ts:7
#, fuzzy
msgid "Reset application layout"
msgstr "画面レイアウトをカスタマイズ"
msgstr "画面レイアウトをリセット"
#: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:219
#: packages/app-desktop/gui/MasterPasswordDialog/Dialog.tsx:220
@@ -4398,7 +4388,7 @@ msgstr "ノートがありません。(+)ボタンを押して新しいノート
#: packages/app-mobile/components/screens/ConfigScreen.tsx:344
msgid "There are unsaved changes."
msgstr ""
msgstr "保存されていない変更があります。"
#: packages/app-desktop/gui/NoteList/NoteList.tsx:512
msgid ""
@@ -4959,12 +4949,12 @@ msgstr "Vim"
#: packages/lib/models/Setting.ts:1705
msgid "Voice typing language files (URL)"
msgstr ""
msgstr "音声入力言語ファイル (URL)"
#: packages/app-mobile/components/screens/Note.tsx:994
#: packages/app-mobile/components/voiceTyping/VoiceTypingDialog.tsx:119
msgid "Voice typing..."
msgstr ""
msgstr "音声入力…"
#: packages/app-mobile/components/screens/ConfigScreen.tsx:83
msgid "Warning"

View File

@@ -1,5 +1,17 @@
# Joplin changelog
## [v2.12.10](https://github.com/laurent22/joplin/releases/tag/v2.12.10) (Pre-release) - 2023-07-30T18:25:58Z
- Improved: Adding support for plugin icons ([#8499](https://github.com/laurent22/joplin/issues/8499)) ([#8408](https://github.com/laurent22/joplin/issues/8408) by [@hubert](https://github.com/hubert))
- Improved: Updated packages gettext-parser (v7.0.1), react-redux (v8.1.1)
- Fixed: [#8370](https://github.com/laurent22/joplin/issues/8370): Fix note drag-drop into markdown editor ([#8571](https://github.com/laurent22/joplin/issues/8571)) ([#8370](https://github.com/laurent22/joplin/issues/8370) by Henry Heino)
- Fixed: Fix CodeMirror context menu not containing correct items ([#8543](https://github.com/laurent22/joplin/issues/8543)) ([#8535](https://github.com/laurent22/joplin/issues/8535) by Henry Heino)
- Fixed: Note imported from Web Clipper is broken after being saved from the Rich Text editor ([#8485](https://github.com/laurent22/joplin/issues/8485))
- Fixed: Preserve empty newlines created by pressing Enter repeatedly in the rich text editor ([#8549](https://github.com/laurent22/joplin/issues/8549)) ([#6055](https://github.com/laurent22/joplin/issues/6055) by Henry Heino)
- Fixed: Text that is pasted in Rich Text editor had extra new lines ([#8476](https://github.com/laurent22/joplin/issues/8476))
- Fixed: Upgrade to electron 25.3.1 ([#8550](https://github.com/laurent22/joplin/issues/8550)) ([#8535](https://github.com/laurent22/joplin/issues/8535) by Henry Heino)
- Security: Fix XSS: Sanitize HTML pasted into the rich text editor.
## [v2.12.9](https://github.com/laurent22/joplin/releases/tag/v2.12.9) (Pre-release) - 2023-07-25T16:06:08Z
- New: Add support for Joplin Cloud email to note functionality ([#8460](https://github.com/laurent22/joplin/issues/8460) by [@pedr](https://github.com/pedr))

View File

@@ -647,6 +647,14 @@
"created_at": "2023-07-26T16:17:02Z",
"repoId": 79162682,
"pullRequestNo": 8560
},
{
"name": "kna",
"id": 77619,
"comment_id": 1656996942,
"created_at": "2023-07-30T02:10:42Z",
"repoId": 79162682,
"pullRequestNo": 8580
}
]
}

View File

@@ -16,10 +16,14 @@ Moreover, by getting a subscription you are supporting the development of the pr
## Do you offer discounts?
We offer a 50% Education Discount for students and teachers. To claim it, please [contact us](mailto:support@joplincloud.com) from your university or school email address. You will then receive a URL you can use to subscribe to Joplin Cloud while benefiting from the 50% discount. This is valid for a whole year and can be renewed for as long as you are in education by contacting us again.
We offer a 50% Education Discount for students and teachers. To claim it, please contact us from your university or school email address. You will then receive a URL you can use to subscribe to Joplin Cloud while benefiting from the 50% discount. This is valid for a whole year and can be renewed for as long as you are in education by contacting us again.
We may also offer bulk discounts for companies, associations and nonprofit organisations. Please [contact us](mailto:support@joplincloud.com) for more details.
## All our services are carbon neutral
## Where is Joplin Cloud data located?
<img style="max-width: 100%; float:right;" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/plans/CarbonNeutral.png" /> Because the protection of the environment is as important as the protection of your data, we made our services carbon neutral. We believe that technology should not come at the expense of the planet, and we are committed to reducing our carbon footprint.<br/><br/>To do this, we invest in various ecological projects such as planting trees, cleaning up polluted areas, cleaning the oceans, and more, through organizations, associations, or companies. We constantly monitor our emissions and offset them through these projects to ensure that we are doing our part in the fight against climate change.<br/><br/>For example, we have teamed up with the non-profit organisation carbone.eco and invested in the reforestation of four hectares of forest in France.
Joplin Cloud data and servers are all located in France (Paris), thus your data benefits from strong data protection regulations including GDPR.
## Joplin Cloud is carbon neutral
We believe that technology should not come at the expense of the planet, and we are committed to reducing our carbon footprint. For example, we have teamed up with the non-profit organisation carbone.eco and invested in the reforestation of four hectares of forest in France.

View File

@@ -4559,6 +4559,8 @@ __metadata:
execa: 4.1.0
fs-extra: 11.1.1
gulp: 4.0.2
http-browserify: 1.7.0
https-browserify: 1.0.0
jest: 29.5.0
jest-environment-jsdom: 29.5.0
jetifier: 2.0.0
@@ -4569,6 +4571,7 @@ __metadata:
md5-file: 5.0.0
metro-react-native-babel-preset: 0.73.9
nodemon: 2.0.22
os-browserify: 0.3.0
path-browserify: 1.0.1
prop-types: 15.8.1
punycode: 2.3.0
@@ -4587,7 +4590,7 @@ __metadata:
react-native-fs: 2.20.0
react-native-gesture-handler: 2.12.0
react-native-get-random-values: 1.9.0
react-native-image-picker: 5.4.2
react-native-image-picker: 5.6.0
react-native-image-resizer: 1.4.5
react-native-localize: 3.0.2
react-native-modal-datetime-picker: 15.0.1
@@ -4596,7 +4599,7 @@ __metadata:
react-native-quick-actions: 0.3.13
react-native-reanimated: 3.3.0
react-native-rsa-native: 2.0.5
react-native-safe-area-context: 4.5.5
react-native-safe-area-context: 4.6.0
react-native-securerandom: 1.0.1
react-native-share: 8.2.2
react-native-sqlite-storage: 6.0.1
@@ -8824,6 +8827,13 @@ __metadata:
languageName: node
linkType: hard
"Base64@npm:~0.2.0":
version: 0.2.1
resolution: "Base64@npm:0.2.1"
checksum: 7c47e801b52cb9c963ee2cfb9284fbef8a6a34d3bbc5f7503b186ab5fb3a77e3f4a321f14ef20a6b2270d6cc3c89a2a349a538c4690abd2077bbe7caef10272d
languageName: node
linkType: hard
"JSONStream@npm:^1.0.3, JSONStream@npm:^1.0.4, JSONStream@npm:^1.3.4":
version: 1.3.5
resolution: "JSONStream@npm:1.3.5"
@@ -18634,6 +18644,16 @@ __metadata:
languageName: node
linkType: hard
"http-browserify@npm:1.7.0":
version: 1.7.0
resolution: "http-browserify@npm:1.7.0"
dependencies:
Base64: ~0.2.0
inherits: ~2.0.1
checksum: 7891aee4a55a0182bcdd8cd59f1d154a8f9b284e006bced7fbf5e9ae2e6762ec6c7ade7742952c509503f23b2b9b94c791a14a77fc85881aa2c51b3b010d029b
languageName: node
linkType: hard
"http-cache-semantics@npm:^3.8.1":
version: 3.8.1
resolution: "http-cache-semantics@npm:3.8.1"
@@ -18781,7 +18801,7 @@ __metadata:
languageName: node
linkType: hard
"https-browserify@npm:^1.0.0":
"https-browserify@npm:1.0.0, https-browserify@npm:^1.0.0":
version: 1.0.0
resolution: "https-browserify@npm:1.0.0"
checksum: 09b35353e42069fde2435760d13f8a3fb7dd9105e358270e2e225b8a94f811b461edd17cb57594e5f36ec1218f121c160ddceeec6e8be2d55e01dcbbbed8cbae
@@ -25680,7 +25700,7 @@ __metadata:
languageName: node
linkType: hard
"os-browserify@npm:~0.3.0":
"os-browserify@npm:0.3.0, os-browserify@npm:~0.3.0":
version: 0.3.0
resolution: "os-browserify@npm:0.3.0"
checksum: 16e37ba3c0e6a4c63443c7b55799ce4066d59104143cb637ecb9fce586d5da319cdca786ba1c867abbe3890d2cbf37953f2d51eea85e20dd6c4570d6c54bfebf
@@ -27881,13 +27901,13 @@ __metadata:
languageName: node
linkType: hard
"react-native-image-picker@npm:5.4.2":
version: 5.4.2
resolution: "react-native-image-picker@npm:5.4.2"
"react-native-image-picker@npm:5.6.0":
version: 5.6.0
resolution: "react-native-image-picker@npm:5.6.0"
peerDependencies:
react: "*"
react-native: "*"
checksum: a858cb8777c99a8ce9e338c9fb4dc3ab09bef5b23f0751dd9dec7da630cc299d3afdcb479a76db2aa473e9132ad7fb6ae75ef12cf32a12f48684461a0b351212
checksum: 3797ec006c2d1f7b96c088c25d972113ef61f42e499f1bdbc553630acecab613d671a2c7d050029a7b01df144e83992ea2639b33255cfa487bf422943ded419b
languageName: node
linkType: hard
@@ -28005,13 +28025,13 @@ __metadata:
languageName: node
linkType: hard
"react-native-safe-area-context@npm:4.5.5":
version: 4.5.5
resolution: "react-native-safe-area-context@npm:4.5.5"
"react-native-safe-area-context@npm:4.6.0":
version: 4.6.0
resolution: "react-native-safe-area-context@npm:4.6.0"
peerDependencies:
react: "*"
react-native: "*"
checksum: 27c7881fd219cdadf7f05160782e1d6a4d65d2c2fc7bc8a5fc9274d09a12cd5ceae8cc42894284d0741faeaae20bab3b695b5bc77d1f54ec28fb7652f9170e0c
checksum: 419660209eee73f02a5898d0501757409ed6907f1934461bb6c738b93777c7fb9ddb9edd1b18bcec62167ebacec904428c9257b4b233c77d18a226a486d30d41
languageName: node
linkType: hard