1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-09-02 20:46:21 +02:00

Compare commits

...

17 Commits

Author SHA1 Message Date
Laurent Cozic
b678d20d76 Android 2.5.5 2021-10-31 11:25:07 +00:00
Laurent Cozic
1f96eb764d Lock files 2021-10-31 10:38:11 +00:00
Laurent Cozic
e453cd36c5 Tools: Build app before releasing Android app 2021-10-31 10:35:26 +00:00
Laurent Cozic
232128c558 Android 2.5.4 2021-10-31 10:29:15 +00:00
Laurent Cozic
dbdb82d0a9 Desktop release v2.5.8 2021-10-31 10:05:33 +00:00
Laurent Cozic
14ddf40fa4 Fixed French translation 2021-10-31 10:03:37 +00:00
Laurent Cozic
4128be9d6c Mobile: Capitalise first word of sentence in beta editor 2021-10-31 09:34:26 +00:00
Brett Bender
8de9032321 Deskop: Fixed shortcut to focus the note body (#5597) 2021-10-30 18:00:01 +01:00
Laurent Cozic
0b01b5b0ef Desktop, Mobile: Resolves #5593: Enable safe mode for Markdown editor too 2021-10-30 17:51:19 +01:00
Laurent Cozic
aa3cbbd165 Desktop, Mobile: Fixes #5593: Do not render very large code blocks to prevent app from freezing 2021-10-30 17:47:16 +01:00
Laurent Cozic
2d1a6da1cb Revert "Desktop: Upgrade to Electron 15.1.3"
No longer necessary because it was to try to fix this bug, but it
doesn't fix it:

https://discourse.joplinapp.org/t/20702/32

This reverts commit 9704b29c03.
2021-10-30 15:20:33 +01:00
Laurent Cozic
365e152758 Mobile: Add padding around beta text editor 2021-10-30 15:18:31 +01:00
Andreas Deininger
6393996694 Doc: Fixing typos (#5644) 2021-10-30 10:45:02 +01:00
Laurent Cozic
f7a18bac2a Server: Add unique constraint on name and owner ID of items table
In theory, the server enforces uniquness because when doing a PUT
operation it either creates the items if it doesn't exist, or overwrite
it. However, there's race condition that makes it possible for multiple
items with the same name being created per user. So we add this
constraint to ensure that any additional query would fail (which can be
recovered by repeating the request).
2021-10-30 10:37:56 +01:00
Laurent Cozic
bb06e56a05 Added better-sqlite database driver, although we cannot use it for now 2021-10-29 18:48:13 +01:00
Laurent Cozic
4e1f315151 Desktop release v2.5.7 2021-10-29 12:12:30 +01:00
Laurent Cozic
9704b29c03 Desktop: Upgrade to Electron 15.1.3 2021-10-29 12:11:38 +01:00
34 changed files with 217 additions and 74 deletions

View File

@@ -693,9 +693,6 @@ packages/app-desktop/services/commands/stateToWhenClauseContext.js.map
packages/app-desktop/services/commands/types.d.ts
packages/app-desktop/services/commands/types.js
packages/app-desktop/services/commands/types.js.map
packages/app-desktop/services/e2ee.d.ts
packages/app-desktop/services/e2ee.js
packages/app-desktop/services/e2ee.js.map
packages/app-desktop/services/plugins/PlatformImplementation.d.ts
packages/app-desktop/services/plugins/PlatformImplementation.js
packages/app-desktop/services/plugins/PlatformImplementation.js.map
@@ -969,6 +966,9 @@ packages/lib/commands/synchronize.js.map
packages/lib/components/EncryptionConfigScreen/utils.d.ts
packages/lib/components/EncryptionConfigScreen/utils.js
packages/lib/components/EncryptionConfigScreen/utils.js.map
packages/lib/database-driver-better-sqlite.d.ts
packages/lib/database-driver-better-sqlite.js
packages/lib/database-driver-better-sqlite.js.map
packages/lib/database.d.ts
packages/lib/database.js
packages/lib/database.js.map

6
.gitignore vendored
View File

@@ -676,9 +676,6 @@ packages/app-desktop/services/commands/stateToWhenClauseContext.js.map
packages/app-desktop/services/commands/types.d.ts
packages/app-desktop/services/commands/types.js
packages/app-desktop/services/commands/types.js.map
packages/app-desktop/services/e2ee.d.ts
packages/app-desktop/services/e2ee.js
packages/app-desktop/services/e2ee.js.map
packages/app-desktop/services/plugins/PlatformImplementation.d.ts
packages/app-desktop/services/plugins/PlatformImplementation.js
packages/app-desktop/services/plugins/PlatformImplementation.js.map
@@ -952,6 +949,9 @@ packages/lib/commands/synchronize.js.map
packages/lib/components/EncryptionConfigScreen/utils.d.ts
packages/lib/components/EncryptionConfigScreen/utils.js
packages/lib/components/EncryptionConfigScreen/utils.js.map
packages/lib/database-driver-better-sqlite.d.ts
packages/lib/database-driver-better-sqlite.js
packages/lib/database-driver-better-sqlite.js.map
packages/lib/database.d.ts
packages/lib/database.js
packages/lib/database.js.map

View File

@@ -28,7 +28,7 @@
"linter": "./node_modules/.bin/eslint --resolve-plugins-relative-to . --fix --quiet --ext .js --ext .jsx --ext .ts --ext .tsx",
"postinstall": "npm run bootstrap --no-ci && npm run build",
"publishAll": "git pull && npm run build && lerna version --yes --no-private --no-git-tag-version && gulp completePublishAll",
"releaseAndroid": "export PATH=\"/usr/local/opt/openjdk@11/bin:$PATH\" && node packages/tools/release-android.js",
"releaseAndroid": "npm run build && export PATH=\"/usr/local/opt/openjdk@11/bin:$PATH\" && node packages/tools/release-android.js",
"releaseAndroidClean": "node packages/tools/release-android.js",
"releaseCli": "node packages/tools/release-cli.js",
"releaseClipper": "node packages/tools/release-clipper.js",

View File

@@ -147,7 +147,9 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
if (props.visiblePanes.indexOf('editor') >= 0) {
editorRef.current.focus();
} else {
webviewRef.current.wrappedInstance.focus();
// If we just call wrappedInstance.focus() then the iframe is focused,
// but not its content, such that scrolling up / down with arrow keys fails
webviewRef.current.wrappedInstance.send('focus');
}
} else {
commandProcessed = false;
@@ -812,6 +814,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
onChange={codeMirror_change}
onScroll={editor_scroll}
onEditorPaste={onEditorPaste}
isSafeMode={props.isSafeMode}
/>
</div>
);

View File

@@ -92,6 +92,7 @@ export interface EditorProps {
onChange: any;
onScroll: any;
onEditorPaste: any;
isSafeMode: boolean;
}
function Editor(props: EditorProps, ref: any) {
@@ -149,11 +150,13 @@ function Editor(props: EditorProps, ref: any) {
useEffect(() => {
if (!editorParent.current) return () => {};
// const userOptions = eventManager.filterEmit('codeMirrorOptions', {});
const userOptions = {};
const cmOptions = Object.assign({}, {
const safeOptions: Record<string, any> = {
value: props.value,
};
const unsafeOptions: Record<string, any> = {
screenReaderLabel: props.value,
theme: props.codeMirrorTheme,
mode: props.mode,
@@ -167,7 +170,17 @@ function Editor(props: EditorProps, ref: any) {
spellcheck: true,
allowDropFileTypes: [''], // disable codemirror drop handling
keyMap: props.keyMap ? props.keyMap : 'default',
}, userOptions);
};
let cmOptions: Record<string, any> = { ...safeOptions };
if (!props.isSafeMode) {
cmOptions = {
...cmOptions,
...unsafeOptions,
...userOptions,
};
}
const cm = CodeMirror(editorParent.current, cmOptions);
setEditor(cm);

View File

@@ -409,6 +409,7 @@ function NoteEditor(props: NoteEditorProps) {
plugins: props.plugins,
fontSize: Setting.value('style.editor.fontSize'),
contentMaxWidth: props.contentMaxWidth,
isSafeMode: props.isSafeMode,
};
let editor = null;
@@ -611,6 +612,7 @@ const mapStateToProps = (state: AppState) => {
'setTags',
], whenClauseContext)[0],
contentMaxWidth: state.settings['style.editor.contentMaxWidth'],
isSafeMode: state.settings.isSafeMode,
};
};

View File

@@ -43,6 +43,7 @@ export interface NoteEditorProps {
setTagsToolbarButtonInfo: ToolbarButtonInfo;
richTextBannerDismissed: boolean;
contentMaxWidth: number;
isSafeMode: boolean;
}
export interface NoteBodyEditorProps {
@@ -74,6 +75,7 @@ export interface NoteBodyEditorProps {
plugins: PluginStates;
fontSize: number;
contentMaxWidth: number;
isSafeMode: boolean;
}
export interface FormNote {

View File

@@ -146,6 +146,10 @@ class NoteTextViewerComponent extends React.Component<Props, any> {
send(channel: string, arg0: any = null, arg1: any = null) {
const win = this.webviewRef_.current.contentWindow;
if (channel === 'focus') {
win.postMessage({ target: 'webview', name: 'focus', data: {} }, '*');
}
if (channel === 'setHtml') {
win.postMessage({ target: 'webview', name: 'setHtml', data: { html: arg0, options: arg1 } }, '*');
}

View File

@@ -197,6 +197,17 @@
let checkAllImageLoadedIID_ = null;
ipc.focus = (event) => {
const dummyID = 'joplin-content-focus-dummy';
if (! document.getElementById(dummyID)) {
const focusDummy = '<div style="width: 0; height: 0; overflow: hidden"><a id="' + dummyID + '" href="#">focus dummy</a></div>';
contentElement.insertAdjacentHTML("afterbegin", focusDummy);
}
const scrollTop = contentElement.scrollTop;
document.getElementById(dummyID).focus();
contentElement.scrollTop = scrollTop;
}
ipc.setHtml = (event) => {
const html = event.html;

View File

@@ -1,12 +1,12 @@
{
"name": "@joplin/app-desktop",
"version": "2.5.6",
"version": "2.5.8",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@joplin/app-desktop",
"version": "2.5.6",
"version": "2.5.8",
"license": "MIT",
"dependencies": {
"@electron/remote": "^2.0.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/app-desktop",
"version": "2.5.6",
"version": "2.5.8",
"description": "Joplin for Desktop",
"main": "main.js",
"private": true,

View File

@@ -141,8 +141,8 @@ android {
applicationId "net.cozic.joplin"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2097654
versionName "2.5.3"
versionCode 2097656
versionName "2.5.5"
ndk {
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}

View File

@@ -32,6 +32,14 @@ function logMessage(...msg: any[]) {
postMessage('onLog', { value: msg });
}
// For an example on how to customize the theme, see:
//
// https://github.com/codemirror/theme-one-dark/blob/main/src/one-dark.ts
//
// Use Safari developer tools to view the content of the CodeMirror iframe while
// the app is running. It seems that what appears as ".ͼ1" in the CSS is the
// equivalent of "&" in the theme object. So to target ".ͼ1.cm-focused", you'd
// use '&.cm-focused' in the theme.
const createTheme = (theme: any): Extension => {
const baseTheme = EditorView.baseTheme({
'&': {
@@ -40,6 +48,10 @@ const createTheme = (theme: any): Extension => {
fontFamily: theme.fontFamily,
fontSize: `${theme.fontSize}px`,
},
'&.cm-focused': {
outline: 'none',
},
});
const appearanceTheme = EditorView.theme({}, { dark: theme.appearance === 'dark' });
@@ -133,6 +145,7 @@ export function initCodeMirror(parentElement: any, initialText: string, theme: a
drawSelection(),
highlightSpecialChars(),
EditorView.lineWrapping,
EditorView.contentAttributes.of({ autocapitalize: 'sentence' }),
defaultHighlightStyle.fallback,
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
if (viewUpdate.docChanged) {

View File

@@ -188,8 +188,8 @@ function useHtml(css: string): string {
${css}
</style>
</head>
<body style="margin:0; height:100vh; width:100vh; width:100vw; min-width:100vw;">
<div class="CodeMirror" style="height:100%;"></div>
<body style="margin:0; height:100vh; width:100vh; width:100vw; min-width:100vw; box-sizing: border-box; padding: 10px;">
<div class="CodeMirror" style="height:100%;" autocapitalize="on"></div>
</body>
</html>
`

View File

@@ -493,7 +493,7 @@ SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
DoubleConversion: cf9b38bf0b2d048436d9a82ad2abe1404f11e7de
FBLazyVector: e686045572151edef46010a6f819ade377dfeb4b
FBReactNativeSpec: d2f54de51f69366bd1f5c1fb9270698dce678f8d
FBReactNativeSpec: 009b310a5134a345e702b4402de70b5ee2bb4832
glog: 73c2498ac6884b13ede40eda8228cb1eee9d9d62
JoplinCommonShareExtension: 270b4f8eb4e22828eeda433a04ed689fc1fd09b5
JoplinRNShareExtension: 7137e9787374e1b0797ecbef9103d1588d90e403

View File

@@ -0,0 +1,52 @@
// This is a driver for better-sqlite3. It may be interesting to use it instead
// of node-sqlite because it breaks all the time when we try to compile any app.
// The performance improvement probably won't matter.
//
// The issue however is that better-sqlite3 uses the option SQLITE_DQS=0, which
// disallows using double quotes around strings, and that's what we're using
// everywhere. So the only way to make it work would be to do a custom
// compilation, as described there, and set SQLITE_DQS=1:
//
// https://github.com/JoshuaWise/better-sqlite3/blob/master/docs/compilation.md
const Database = require('better-sqlite3');
interface Options {
name: string;
}
export default class DatabaseDriverBetterSqlite {
private db_: any = null;
public open(options: Options) {
this.db_ = new Database(options.name);
}
public sqliteErrorToJsError(error: any, sql: string = null, params: any[] = null) {
console.error(error.toString(), ' ---- ', sql, params);
const msg = [error.toString()];
if (sql) msg.push(sql);
if (params) msg.push(params);
const output: any = new Error(msg.join(': '));
if (error.code) output.code = error.code;
return output;
}
public async selectOne(sql: string, params: any[] = null) {
return this.db_.prepare(sql).get(params ? params : []);
}
public async selectAll(sql: string, params: any[] = null) {
return this.db_.prepare(sql).all(params ? params : []);
}
public async exec(sql: string, params: any[] = null) {
return this.db_.prepare(sql).run(params ? params : []);
}
lastInsertId() {
throw new Error('NOT IMPLEMENTED');
}
}

View File

@@ -393,6 +393,24 @@ export default class MdToHtml {
this.cachedOutputs_ = {};
}
private removeLastNewLine(s: string): string {
if (s[s.length - 1] === '\n') {
return s.substr(0, s.length - 1);
} else {
return s;
}
}
// Rendering large code blocks can freeze the app so we disable it in
// certain cases:
// https://github.com/laurent22/joplin/issues/5593#issuecomment-947374218
private shouldSkipHighlighting(str: string, lang: string): boolean {
if (lang && !hljs.getLanguage(lang)) lang = '';
if (str.length >= 1000 && !lang) return true;
if (str.length >= 512000 && lang) return true;
return false;
}
// "theme" is the theme as returned by themeStyle()
public async render(body: string, theme: any = null, options: RenderOptions = null): Promise<RenderResult> {
@@ -455,29 +473,32 @@ export default class MdToHtml {
// The strings includes the last \n that is part of the fence,
// so we remove it because we need the exact code in the source block
const trimmedStr = str.replace(/(.*)\n$/, '$1');
const trimmedStr = this.removeLastNewLine(str);
const sourceBlockHtml = `<pre class="joplin-source" data-joplin-language="${lang}" data-joplin-source-open="\`\`\`${lang}&#10;" data-joplin-source-close="&#10;\`\`\`">${markdownIt.utils.escapeHtml(trimmedStr)}</pre>`;
try {
let hlCode = '';
const cacheKey = md5(`${str}_${lang}`);
if (options.codeHighlightCacheKey && this.cachedHighlightedCode_[cacheKey]) {
hlCode = this.cachedHighlightedCode_[cacheKey];
} else {
if (lang && hljs.getLanguage(lang)) {
// hlCode = hljs.highlight(lang, trimmedStr, true).value;
hlCode = hljs.highlight(trimmedStr, { language: lang, ignoreIllegals: true }).value;
} else {
hlCode = hljs.highlightAuto(trimmedStr).value;
}
this.cachedHighlightedCode_[cacheKey] = hlCode;
}
outputCodeHtml = hlCode;
} catch (error) {
if (this.shouldSkipHighlighting(trimmedStr, lang)) {
outputCodeHtml = markdownIt.utils.escapeHtml(trimmedStr);
} else {
try {
let hlCode = '';
const cacheKey = md5(`${str}_${lang}`);
if (options.codeHighlightCacheKey && this.cachedHighlightedCode_[cacheKey]) {
hlCode = this.cachedHighlightedCode_[cacheKey];
} else {
if (lang && hljs.getLanguage(lang)) {
hlCode = hljs.highlight(trimmedStr, { language: lang, ignoreIllegals: true }).value;
} else {
hlCode = hljs.highlightAuto(trimmedStr).value;
}
this.cachedHighlightedCode_[cacheKey] = hlCode;
}
outputCodeHtml = hlCode;
} catch (error) {
outputCodeHtml = markdownIt.utils.escapeHtml(trimmedStr);
}
}
const html = `<div class="joplin-editable">${sourceBlockHtml}<pre class="hljs"><code>${outputCodeHtml}</code></pre></div>`;

View File

@@ -0,0 +1,14 @@
import { Knex } from 'knex';
import { DbConnection } from '../db';
export async function up(db: DbConnection): Promise<any> {
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
table.unique(['name', 'owner_id']);
});
}
export async function down(db: DbConnection): Promise<any> {
await db.schema.alterTable('items', (table: Knex.CreateTableBuilder) => {
table.dropUnique(['name', 'owner_id']);
});
}

View File

@@ -13,8 +13,10 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.0\n"
"X-Generator: Poedit 2.4.2\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
#: packages/app-cli/app/app-gui.js:452
msgid "To delete a tag, untag the associated notes."
@@ -1473,15 +1475,15 @@ msgstr "Mot de passe maître"
#: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.js:118
msgid "Source: "
msgstr "Source :"
msgstr "Source : "
#: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.js:121
msgid "Created: "
msgstr "Créé :"
msgstr "Créé : "
#: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.js:124
msgid "Updated: "
msgstr "Mis à jour :"
msgstr "Mis à jour : "
#: packages/app-desktop/gui/EncryptionConfigScreen/EncryptionConfigScreen.js:129
msgid "Disable"

View File

@@ -17,9 +17,9 @@ Then, in the directory where you plan to develop the plugin, run:
yo joplin
This will generate the basic scafolding of the plugin. At the root of it, there are a number of configuration files which you normally won't need to change. Then the `src/` directory will contain your code. By default, the project uses TypeScript, but you are free to use plain JavaScript too - eventually the project is compiled to plain JS in any case.
This will generate the basic scaffolding of the plugin. At the root of it, there are a number of configuration files which you normally won't need to change. Then the `src/` directory will contain your code. By default, the project uses TypeScript, but you are free to use plain JavaScript too - eventually the project is compiled to plain JS in any case.
The `src/` directory also contains a [manifest.json](https://github.com/laurent22/joplin/blob/dev/readme/api/references/plugin_manifest.md) file, which contains the various information about the plugin that was set in the inital generation of the scaffolding, such as its name, homepage URL, etc. You can edit this at any time, but editing it after it has been published may cause users to have to download it again.
The `src/` directory also contains a [manifest.json](https://github.com/laurent22/joplin/blob/dev/readme/api/references/plugin_manifest.md) file, which contains the various information about the plugin that was set in the initial generation of the scaffolding, such as its name, homepage URL, etc. You can edit this at any time, but editing it after it has been published may cause users to have to download it again.
## Setup Source Control

View File

@@ -81,7 +81,7 @@ Then you will resume fetching the results using this query:
curl http://localhost:41184/notes?order_by=updated_time&order_dir=ASC&limit=10&page=2
Eventually you will get some results that do not contain an "has_more" paramater, at which point you will have retrieved all the results
Eventually you will get some results that do not contain an "has_more" parameter, at which point you will have retrieved all the results
As an example the pseudo-code below could be used to fetch all the notes:
@@ -126,7 +126,7 @@ To retrieve all the tags that start with `project-`: **GET /search?query=project
# Item type IDs
Item type IDs might be refered to in certain object you will retrieve from the API. This is the correspondance between name and ID:
Item type IDs might be referred to in certain object you will retrieve from the API. This is the correspondence between name and ID:
Name | Value
---- | -----

View File

@@ -1,5 +1,11 @@
# Joplin Android app changelog
## [android-v2.5.5](https://github.com/laurent22/joplin/releases/tag/android-v2.5.5) (Pre-release) - 2021-10-31T11:03:16Z
- New: Add padding around beta text editor (365e152)
- Improved: Capitalise first word of sentence in beta editor (4128be9)
- Fixed: Do not render very large code blocks to prevent app from freezing (#5593)
## [android-v2.5.3](https://github.com/laurent22/joplin/releases/tag/android-v2.5.3) (Pre-release) - 2021-10-28T21:47:18Z
- New: Add support for public-private key pairs and improved master password support (#5438)

View File

@@ -31,7 +31,7 @@ To do so, first enable developer mode in [chrome://extensions/](chrome://extensi
## In Firefox
- Open [about:debugging](about:debugging) in Firefox.
- Make sure the checkox "Enable add-on debugging" is ticked.
- Make sure the checkbox "Enable add-on debugging" is ticked.
- Scroll down to the Joplin Web Clipper extension.
- Click on "Debugging" - that should open a new console window.

View File

@@ -24,4 +24,4 @@ Tap on the **burger icon ≡** in the top left corner, and select **Configuratio
## CLI
Type `:help config` for information on how to set config values nad for the complete list of available options.
Type `:help config` for information on how to set config values and for the complete list of available options.

View File

@@ -8,7 +8,7 @@ Most of all, your donation will make it possible to keep up the current developm
Platform | Link
--- | ---
Paypal | [![Donate on PayPal](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=E8JMYD2LQ8MMA&lc=GB&item_name=Joplin+Development&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted) |
PayPal | [![Donate on PayPal](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=E8JMYD2LQ8MMA&lc=GB&item_name=Joplin+Development&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted) |
GitHub Sponsor | [![Sponsor on GitHub](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/GitHub-Badge.svg)](https://github.com/sponsors/laurent22/)
Patreon | [![Become a patron](https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Patreon-Badge.svg)](https://www.patreon.com/joplin)
Bank Transfer | **IBAN:** FR76 4061 8803 5200 0400 7415 938<br>**BIC/SWIFT:** BOUS FRPP XXX

View File

@@ -1,4 +1,4 @@
# 1.Idea - Create documenation hub
# 1.Idea - Create documentation hub
- Make a screening of available options of how apps to be utilized to organize documentation better and simplified access to information.
You can start with:
- [Read the Docs](https://readthedocs.org/)

View File

@@ -4,27 +4,27 @@
Joplin has a young but well proven history. It all started by single idea but is rising more and more commitment as well as demands.
Joplin is about to make another big step to answers these demands by being an organization at Google Summer of Code 2020.
During the young history of the GSoC campaign it was noticed that it would be a greate help if documenation is centralized and making it a continuous read. The current documentation tells when to do what and how clearly. In addition, the source code of Joplin is clean and well strucutred, so it is easy to understand.
Nevertheless, there are additional and essential information scattered around on the Forum and GitHub which rely on an active community, so that are being shared with them who need them. It can be said that this happens very well but it is aggreed that this situation has to be improved to free resources for working on the source coden and lower entry barriers for new contributors.
During the young history of the GSoC campaign it was noticed that it would be a great help if documentation is centralized and making it a continuous read. The current documentation tells when to do what and how clearly. In addition, the source code of Joplin is clean and well structured, so it is easy to understand.
Nevertheless, there are additional and essential information scattered around on the Forum and GitHub which rely on an active community, so that are being shared with them who need them. It can be said that this happens very well but it is agreed that this situation has to be improved to free resources for working on the source code and lower entry barriers for new contributors.
For these reasons, all students and Joplin users and developers are welcome to participate in the hopefully first year Summer of Docs program with Joplin. Here's how.
Mentors, administrators and students: read [Season of Docs](https://developers.google.com/season-of-docs) occasionally. Also read the [Season of Docs FAQ](https://developers.google.com/season-of-docs/docs/faq).
**Most IMPORTANT, read this page carefully, line by line. We don't want to quote pharagraphs from this page answering question in the forum.
Moreover, watch/subscribe the topic [GSoC 2020 live blog](https://discourse.joplinapp.org/t/gsoc-2020-live-blog/6219) as this page here contains rather static content whereas the mentioned topic is updated much more freuqently.**
**Most IMPORTANT, read this page carefully, line by line. We don't want to quote paragraphs from this page answering question in the forum.
Moreover, watch/subscribe the topic [GSoC 2020 live blog](https://discourse.joplinapp.org/t/gsoc-2020-live-blog/6219) as this page here contains rather static content whereas the mentioned topic is updated much more frequently.**
All participants will need a Google account in order to join the program. So, save time and create one now. In addition, all participants need to join the [Joplin Forum](https://discourse.joplinapp.org).
---
# Instructions for students
Students wishing to participate in Season of Docs must realize, that this is a important professional opportunity. You will be required to produce applicable and readable documenation for Joplin in 3 months. Your mentors, will dedicate a portion of their time to mentoring you. Therefore, we seek candidates who are committed to helping Joplin and its community long-term and are willing to both do quality work, and be proactive in communicating with your mentor(s).
Students wishing to participate in Season of Docs must realize, that this is a important professional opportunity. You will be required to produce applicable and readable documentation for Joplin in 3 months. Your mentors, will dedicate a portion of their time to mentoring you. Therefore, we seek candidates who are committed to helping Joplin and its community long-term and are willing to both do quality work, and be proactive in communicating with your mentor(s).
You don't have to be a proven technical writter - in fact, this whole program is meant to facilitate to support Joplin and other Open Source communities by techinal writters. However, experience in technical writting and/or coding experience is welcome.
You don't have to be a proven technical writer - in fact, this whole program is meant to facilitate to support Joplin and other Open Source communities by technical writers. However, experience in technical writing and/or coding experience is welcome.
In general it can be said, that question shall be asked early and clearly, given everyone the possibility to understand why you want to have this question answered and how it helps to achieve the project's goal.
Before you can be accepted as a student we expect you to communicate very activily with the community and contributors and summerize what could help them most and link that work on your proposal.
Before you can be accepted as a student we expect you to communicate very actively with the community and contributors and summarize what could help them most and link that work on your proposal.
If your idea is related to codebase documentation it is welcome that you fix little bugs. You may browse the GitHub Issues to find some simple tasks. See the good first issues which are a good way to make yourself familiar with the code base.
You should start learning the components that you plan on working on before the start date. Support can be found in the forum and on our dedicated discourse channel.
@@ -42,7 +42,7 @@ Students who neglect active communication will be failed!
First of all, please read the above referenced resources and the [GSoC FAQ](https://developers.google.com/open-source/gsoc/faq). Pay special attention to the **Eligibility** section of the FAQ.
We stronly recomment to follow the recommented steps, see next section, closley. It is slightly differs from the steps given for the closed GSoC application period.
We strongly recommend to follow the recommended steps, see next section, closely. It is slightly differs from the steps given for the closed GSoC application period.
The procedure reflects some of the lessons learnt in the GSOC 2020 campaign, so you may compare the recommended steps and scan the change history of the [GSoC 2020 live blog](https://discourse.joplinapp.org/t/gsoc-2020-live-blog/6219).
## Recommended steps
@@ -52,10 +52,10 @@ The procedure reflects some of the lessons learnt in the GSOC 2020 campaign, so
3. Take a look at the [list of ideas](https://joplinapp.org/gsod2020/ideas/). You can have you own idea added by posting it in the [Features category](https://discourse.joplinapp.org/c/features)
4. Come up with project that you're interested in and discuss it in [Features category](https://discourse.joplinapp.org/c/features) if a corresponding does not already exist.
5. Write a first draft and get someone to review it
1. Remember: you must link to work such as commits in your proposal. A private place will be created wihtinn the forum for that purposes.
1. If you want to add functionality to the codebase or documenation, have it approved [Features category](https://discourse.joplinapp.org/c/features)
1. Remember: you must link to work such as commits in your proposal. A private place will be created within the forum for that purposes.
1. If you want to add functionality to the codebase or documentation, have it approved [Features category](https://discourse.joplinapp.org/c/features)
1. **IMPORTANT**: If you contribute to the codebase do only one contribution at a time and wait until it is approved.
6. Submit your proposal to the mentors writting a private message at `@mentors` in the [Joplin Forum](https://discourse.joplinapp.org) and wait for their feedback
6. Submit your proposal to the mentors writing a private message at `@mentors` in the [Joplin Forum](https://discourse.joplinapp.org) and wait for their feedback
8. Submit proposal using [Google's web interface](https://summerofcode.withgoogle.com/) well ahead of the deadline. You can update it at anytime, even the final proposal.
9. Submit proof of enrolment well ahead of the deadline

View File

@@ -4,6 +4,6 @@ Pre-releases are available for the desktop application. They are pretty much lik
You can help the development of Joplin by choosing to receive these early releases when updating the application. If you find any bug or other issue, please report it on [GitHub](https://github.com/laurent22/joplin/issues) or the forum (if you do not have a GitHub account). Any bug report during the pre-release phase is invaluable to us, as it allows making the app more reliable before making it available to more people.
In general it is safe to use these pre-releases as they do not include any experimental or unstable features. Hundreds of users run them without any issue. Morever even if you do find an issue, you can report it and it is usually fixed very quickly as these bugs are given the highest priority.
In general it is safe to use these pre-releases as they do not include any experimental or unstable features. Hundreds of users run them without any issue. Moreover even if you do find an issue, you can report it and it is usually fixed very quickly as these bugs are given the highest priority.
To have access to these pre-releases, simply go to [Configuration &gt; General](https://github.com/laurent22/joplin/blob/dev/readme/config_screen.md) and tick the box "**Get pre-releases when checking for updates**".

View File

@@ -12,7 +12,7 @@ The user can copy the token in the Clipper configuration page and provide it dir
The token can also be requested programmatically, as is done for the web clipper extension. It works as below:
- The client calls `POST /auth`. The server responds with `{ auth_token: "AUTH_TOKEN" }`. This `auth_token` is different from the regular token - it is just used to authentify the client.
- The client calls `POST /auth`. The server responds with `{ auth_token: "AUTH_TOKEN" }`. This `auth_token` is different from the regular token - it is just used to authenticate the client.
- The application displays a message asking the user to Accept or Reject the access request.

View File

@@ -64,13 +64,13 @@ Enabling/disabling E2EE while two clients are in sync might have an unintuitive
- Although messy, Joplin supports having some clients send encrypted items and others unencrypted ones. The situation gets resolved once all the clients have the same E2EE settings.
- Currently, there is no way to delete encryption keys if you do not need them anymore or if you disabled the encryption completely. You will get a persistant notification to provide a Master Key password on a new device, even if encryption is disabled. Entering the Master Key(s) password and still having the encryption disabled will get rid of the notification. See [Delete E2EE Master Keys](https://discourse.joplinapp.org/t/delete-e2ee-master-keys/906) for more info.
- Currently, there is no way to delete encryption keys if you do not need them anymore or if you disabled the encryption completely. You will get a persistent notification to provide a Master Key password on a new device, even if encryption is disabled. Entering the Master Key(s) password and still having the encryption disabled will get rid of the notification. See [Delete E2EE Master Keys](https://discourse.joplinapp.org/t/delete-e2ee-master-keys/906) for more info.
## Types of keys
There are two types of key:
- **Data keys**, which are used to encrypt Joplin items, such as notes, notebooks, tags, etc. when E2EE is ernabled. A data key is generated when the user enables E2EE. Data keys are also dynamically generated when a user shares a notebook with another user. In this case, we create a separate key, so that the recipient can only decrypt this specific notebook.
- **Data keys**, which are used to encrypt Joplin items, such as notes, notebooks, tags, etc. when E2EE is enabled. A data key is generated when the user enables E2EE. Data keys are also dynamically generated when a user shares a notebook with another user. In this case, we create a separate key, so that the recipient can only decrypt this specific notebook.
- **Public-private key pairs**, which are used to transfer secrets between users.
@@ -97,4 +97,4 @@ At this point, both users have a copy of the key and can share notes over E2EE.
A user can only have one PPK.
PPKs are generated automatically when E2EE is enabled and when the user synchronises. They are then stored in info.json on the sync target. The key is genrated during sync because otherwise multiple clients could generate a PPK, and then there would be a conflict to decide which PPK should be kept. By doing it during sync, it ensures that only one PPK is generated because the synchronizer fetches first info.json - and only generates a PPK if none is already present.
PPKs are generated automatically when E2EE is enabled and when the user synchronises. They are then stored in info.json on the sync target. The key is generated during sync because otherwise multiple clients could generate a PPK, and then there would be a conflict to decide which PPK should be kept. By doing it during sync, it ensures that only one PPK is generated because the synchronizer fetches first info.json - and only generates a PPK if none is already present.

View File

@@ -12,11 +12,11 @@ The events are tied to a particular parent ID - in other words it's only possibl
## What is a change event
An event can be "create", "update" or "detete" and is associated with a given file. The client uses this info to apply the change locally - creating, updating or deleting the file as needed.
An event can be "create", "update" or "delete" and is associated with a given file. The client uses this info to apply the change locally - creating, updating or deleting the file as needed.
Attached to the event, is also a copy of the file metadata, so the client doesn't need to a do a second request to fetch it.
Internally, the event also stores the file name and parent ID. This is used when an item is deleted since in that case the item ID only would not be sufficient to know where the item was initally stored.
Internally, the event also stores the file name and parent ID. This is used when an item is deleted since in that case the item ID only would not be sufficient to know where the item was initially stored.
## Event compression
@@ -88,4 +88,4 @@ The client would then follow this logic:
- If the file is present, delete it.
- If it is not, skip the event (not an error).
It might seem we could derive the "create" events simply by looking at the files in the directory - all files that are there would implicitely have a "create" event. The issue however is that it's not possible to reliably iterate over the files in a folder, because they might change in the meantime. The change events on the other hand provide an ID that can be used reliably to iterate over changes, and to resume at any time.
It might seem we could derive the "create" events simply by looking at the files in the directory - all files that are there would implicitly have a "create" event. The issue however is that it's not possible to reliably iterate over the files in a folder, because they might change in the meantime. The change events on the other hand provide an ID that can be used reliably to iterate over changes, and to resume at any time.

View File

@@ -13,7 +13,7 @@ The process to share is then:
- First, the sharer calls `POST /api/shares` with the notebook ID that needs to be shared.
- Then invitations can be sent by calling `POST /api/share_users` and providing the share ID and recipient email.
- The recipient accept or reject the application by setting the status onn the `share_users` object (which corresponds to an invitation).
- The recipient accept or reject the application by setting the status on the `share_users` object (which corresponds to an invitation).
Once share is setup, the client recursively goes through all notes, sub-notebooks and resources within the shared notebook, and set their `share_id` property. Basically any item within the notebook should have this property set. Then all these items are synchronized.
@@ -21,7 +21,7 @@ On the server, a service is running at regular interval to check the `share_id`
### Why is the share_id set on the client and not the server?
Technically, the server would only need to know the root shared folder, and from that can be find out its children. This approach was tried but it makes the system much more complex because some information is lost after sync - in particular when notes or notebooks are moved out of folders, when resources are attached or removed, etc. Keeping track of all this is possible but complex and innefficient.
Technically, the server would only need to know the root shared folder, and from that can be find out its children. This approach was tried but it makes the system much more complex because some information is lost after sync - in particular when notes or notebooks are moved out of folders, when resources are attached or removed, etc. Keeping track of all this is possible but complex and inefficient.
On the other hand, all that information is present on the client. Whenever a notes is moved out a shared folder, or whenever a resources is attached, the changes are tracked, and that can be used to easily assign a `share_id` property. Once this is set, it makes the whole system more simple and reliable.

View File

@@ -64,4 +64,4 @@ If it's lower than the client supported version, the client does not allow sync
If the user click on the link to upgrade, upgradeState becomes MUST_UPGRADE, and the app restarts.
On startup, the app check the upgradeState setting. If it is MUST_UPGRADE it displays the upgrade screen and starts upgrarding. Once done it sets upgradeState back to IDLE, and restart the app.
On startup, the app check the upgradeState setting. If it is MUST_UPGRADE it displays the upgrade screen and starts upgrading. Once done it sets upgradeState back to IDLE, and restart the app.

View File

@@ -292,7 +292,7 @@ The following commands are available in [command-line mode](#command-line-mode):
Possible keys/values:
sync.target Synchronisation target.
The target to synchonise to. Each sync
The target to synchronise to. Each sync
target may have additional parameters which
are named as `sync.NUM.NAME` (all
documented below).