From 71078637db3953b0e58ac2f353d1c1c5399230ff Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 14 Jul 2019 19:56:46 +0100 Subject: [PATCH 01/10] Android release v1.0.281 --- README.md | 2 +- ReactNativeClient/android/app/build.gradle | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4ccec50623..b5c96a6895 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Linux | Get it on Google Play | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.279/joplin-v1.0.279.apk) +Android | Get it on Google Play | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.281/joplin-v1.0.281.apk) iOS | Get it on the App Store | - ## Terminal application diff --git a/ReactNativeClient/android/app/build.gradle b/ReactNativeClient/android/app/build.gradle index 2a9c56d6eb..5f6e3a8267 100644 --- a/ReactNativeClient/android/app/build.gradle +++ b/ReactNativeClient/android/app/build.gradle @@ -94,8 +94,8 @@ android { applicationId "net.cozic.joplin" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 2097515 - versionName "1.0.279" + versionCode 2097517 + versionName "1.0.281" ndk { abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64" } From 8ecc58e1bf3eab9f4d70dd81f690a95ce5cd4428 Mon Sep 17 00:00:00 2001 From: Caleb John Date: Sun, 14 Jul 2019 17:29:09 -0600 Subject: [PATCH 02/10] Desktop: Add support for cinnamon to install script (#1738) --- Joplin_install_and_update.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Joplin_install_and_update.sh b/Joplin_install_and_update.sh index 236f57664f..bf55467c27 100755 --- a/Joplin_install_and_update.sh +++ b/Joplin_install_and_update.sh @@ -71,7 +71,7 @@ if [[ ! -e ~/.joplin/VERSION ]] || [[ $(< ~/.joplin/VERSION) != "$version" ]]; t # Create icon for Gnome echo 'Create Desktop icon.' - if [[ $desktop =~ .*gnome.*|.*kde.*|.*xfce.*|.*mate.*|.*lxqt.*|.*unity.* ]] + if [[ $desktop =~ .*gnome.*|.*kde.*|.*xfce.*|.*mate.*|.*lxqt.*|.*unity.*|.*X-Cinnamon.* ]] then : "${TMPDIR:=/tmp}" # This command extracts to squashfs-root by default and can't be changed... From 7a902bbd254539dea392559cd502b8170b1884de Mon Sep 17 00:00:00 2001 From: "Helmut K. C. Tessarek" Date: Sun, 14 Jul 2019 20:29:44 -0400 Subject: [PATCH 03/10] Desktop, Mobile: Update Markdown plugins: footnote, toc-done-right, anchor (#1741) --- ElectronClient/app/package.json | 6 +++--- ReactNativeClient/package.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ElectronClient/app/package.json b/ElectronClient/app/package.json index 50e1a83508..0fb2cf8899 100644 --- a/ElectronClient/app/package.json +++ b/ElectronClient/app/package.json @@ -110,17 +110,17 @@ "mark.js": "^8.11.1", "markdown-it": "^8.4.1", "markdown-it-abbr": "^1.0.4", - "markdown-it-anchor": "^5.0.2", + "markdown-it-anchor": "^5.2.4", "markdown-it-deflist": "^2.0.3", "markdown-it-emoji": "^1.4.0", - "markdown-it-footnote": "^3.0.1", + "markdown-it-footnote": "^3.0.2", "markdown-it-ins": "^2.0.0", "markdown-it-katex": "^2.0.3", "markdown-it-mark": "^2.0.0", "markdown-it-multimd-table": "^3.2.0", "markdown-it-sub": "^1.0.0", "markdown-it-sup": "^1.0.0", - "markdown-it-toc-done-right": "^4.0.0", + "markdown-it-toc-done-right": "^4.0.2", "md5": "^2.2.1", "mime": "^2.3.1", "moment": "^2.22.2", diff --git a/ReactNativeClient/package.json b/ReactNativeClient/package.json index d7791cd150..d6c13d84aa 100644 --- a/ReactNativeClient/package.json +++ b/ReactNativeClient/package.json @@ -23,17 +23,17 @@ "katex": "^0.10.0", "markdown-it": "^8.4.0", "markdown-it-abbr": "^1.0.4", - "markdown-it-anchor": "^5.0.2", + "markdown-it-anchor": "^5.2.4", "markdown-it-deflist": "^2.0.3", "markdown-it-emoji": "^1.4.0", - "markdown-it-footnote": "^3.0.1", + "markdown-it-footnote": "^3.0.2", "markdown-it-ins": "^2.0.0", "markdown-it-katex": "^2.0.3", "markdown-it-mark": "^2.0.0", "markdown-it-multimd-table": "^3.2.0", "markdown-it-sub": "^1.0.0", "markdown-it-sup": "^1.0.0", - "markdown-it-toc-done-right": "^4.0.0", + "markdown-it-toc-done-right": "^4.0.2", "md5": "^2.2.1", "moment": "^2.18.1", "prop-types": "^15.6.0", From e9c88dfdc4c8eec2caaf8c84f7c299a83a5e19b4 Mon Sep 17 00:00:00 2001 From: "Helmut K. C. Tessarek" Date: Mon, 15 Jul 2019 23:21:46 -0400 Subject: [PATCH 04/10] Update de_DE.po --- CliClient/locales/de_DE.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CliClient/locales/de_DE.po b/CliClient/locales/de_DE.po index 092e29efa2..574cd95251 100644 --- a/CliClient/locales/de_DE.po +++ b/CliClient/locales/de_DE.po @@ -1985,7 +1985,7 @@ msgstr "" #, javascript-format msgid "Links with protocol \"%s\" are not supported" -msgstr "" +msgstr "Verweise mit dem Protokoll \"%s\" sind nicht unterstützt" #, javascript-format msgid "Unsupported image type: %s" From d45d1b4225d6409997356e31323f8fa8fdc9efa1 Mon Sep 17 00:00:00 2001 From: "Helmut K. C. Tessarek" Date: Tue, 16 Jul 2019 10:11:58 -0400 Subject: [PATCH 05/10] Mobile: Show correct time/date (as specified in settings) for note properties (#1749) --- ReactNativeClient/lib/components/screens/note.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReactNativeClient/lib/components/screens/note.js b/ReactNativeClient/lib/components/screens/note.js index fd3d85a514..65de49b52b 100644 --- a/ReactNativeClient/lib/components/screens/note.js +++ b/ReactNativeClient/lib/components/screens/note.js @@ -613,8 +613,8 @@ class NoteScreenComponent extends BaseScreenComponent { const output = []; - const createdDateString = time.unixMsToLocalDateTime(note.user_created_time); - const updatedDateString = time.unixMsToLocalDateTime(note.user_updated_time); + const createdDateString = time.formatMsToLocal(note.user_created_time); + const updatedDateString = time.formatMsToLocal(note.user_updated_time); output.push({ title: _('Created: %s', createdDateString) }); output.push({ title: _('Updated: %s', updatedDateString) }); From 2ba50321d42a6ca355fc37f8f331bd72673fbd5c Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Thu, 18 Jul 2019 18:36:29 +0100 Subject: [PATCH 06/10] Doc: Added contributors --- README.md | 22 ++++++ Tools/build-translation.js | 18 ++--- Tools/package-lock.json | 92 +++++++++++++++++++++++- Tools/package.json | 1 + Tools/tool-utils.js | 9 +++ Tools/update-readme-contributors.js | 108 ++++++++++++++++++++++++++++ 6 files changed, 236 insertions(+), 14 deletions(-) create mode 100644 Tools/update-readme-contributors.js diff --git a/README.md b/README.md index b5c96a6895..8c35ac3727 100644 --- a/README.md +++ b/README.md @@ -401,6 +401,28 @@ Current translations: ![](https://joplinapp.org/images/flags/country-4x3/kr.png) | 한국말 | [ko](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ko.po) | | 87% +# Contributors + + +| | | | | | | | +| :---: | :---: | :---: | :---: | :---: | :---: | :---: | +|
[laurent22](https://api.github.com/users/laurent22) |
[tessus](https://api.github.com/users/tessus) |
[CalebJohn](https://api.github.com/users/CalebJohn) |
[tanrax](https://api.github.com/users/tanrax) |
[rtmkrlv](https://api.github.com/users/rtmkrlv) |
[fmrtn](https://api.github.com/users/fmrtn) |
[gabcoh](https://api.github.com/users/gabcoh) | +|
[Abijeet](https://api.github.com/users/Abijeet) |
[innocuo](https://api.github.com/users/innocuo) |
[matsest](https://api.github.com/users/matsest) |
[marcosvega91](https://api.github.com/users/marcosvega91) |
[petrz12](https://api.github.com/users/petrz12) |
[foxmask](https://api.github.com/users/foxmask) |
[alexdevero](https://api.github.com/users/alexdevero) | +|
[moltenform](https://api.github.com/users/moltenform) |
[zuphilip](https://api.github.com/users/zuphilip) |
[abonte](https://api.github.com/users/abonte) |
[0ndrey](https://api.github.com/users/0ndrey) |
[stweil](https://api.github.com/users/stweil) |
[bradmcl](https://api.github.com/users/bradmcl) |
[RaphaelKimmig](https://api.github.com/users/RaphaelKimmig) | +|
[RenatoXSR](https://api.github.com/users/RenatoXSR) |
[sensor-freak](https://api.github.com/users/sensor-freak) |
[zblesk](https://api.github.com/users/zblesk) |
[chrisb86](https://api.github.com/users/chrisb86) |
[solariz](https://api.github.com/users/solariz) |
[mmahmoudian](https://api.github.com/users/mmahmoudian) |
[maicki](https://api.github.com/users/maicki) | +|
[mjjzf](https://api.github.com/users/mjjzf) |
[sebastienjust](https://api.github.com/users/sebastienjust) |
[Zorbeyd](https://api.github.com/users/Zorbeyd) |
[chenlhlinux](https://api.github.com/users/chenlhlinux) |
[pf-siedler](https://api.github.com/users/pf-siedler) |
[ruuti](https://api.github.com/users/ruuti) |
[s1nceri7y](https://api.github.com/users/s1nceri7y) | +|
[tfinnberg](https://api.github.com/users/tfinnberg) |
[ShuiHuo](https://api.github.com/users/ShuiHuo) |
[ikunya](https://api.github.com/users/ikunya) |
[Shaxine](https://api.github.com/users/Shaxine) |
[bimlas](https://api.github.com/users/bimlas) |
[chaifeng](https://api.github.com/users/chaifeng) |
[charles-e](https://api.github.com/users/charles-e) | +|
[chrmoritz](https://api.github.com/users/chrmoritz) |
[donbowman](https://api.github.com/users/donbowman) |
[dflock](https://api.github.com/users/dflock) |
[einverne](https://api.github.com/users/einverne) |
[Atalanttore](https://api.github.com/users/Atalanttore) |
[eodeluga](https://api.github.com/users/eodeluga) |
[FleischKarussel](https://api.github.com/users/FleischKarussel) | +|
[gmag11](https://api.github.com/users/gmag11) |
[gusbemacbe](https://api.github.com/users/gusbemacbe) |
[Fvbor](https://api.github.com/users/Fvbor) |
[sczhg](https://api.github.com/users/sczhg) |
[Vistaus](https://api.github.com/users/Vistaus) |
[jacobherrington](https://api.github.com/users/jacobherrington) |
[jcgerhard](https://api.github.com/users/jcgerhard) | +|
[jaredcrowe](https://api.github.com/users/jaredcrowe) |
[jmontane](https://api.github.com/users/jmontane) |
[JoelRSimpson](https://api.github.com/users/JoelRSimpson) |
[jony0008](https://api.github.com/users/jony0008) |
[joybinchen](https://api.github.com/users/joybinchen) |
[y-usuzumi](https://api.github.com/users/y-usuzumi) |
[xuhcc](https://api.github.com/users/xuhcc) | +|
[kklas](https://api.github.com/users/kklas) |
[lboullo0](https://api.github.com/users/lboullo0) |
[dbinary](https://api.github.com/users/dbinary) |
[mvonmaltitz](https://api.github.com/users/mvonmaltitz) |
[Marmo](https://api.github.com/users/Marmo) |
[mgroth0](https://api.github.com/users/mgroth0) |
[MichipX](https://api.github.com/users/MichipX) | +|
[NJannasch](https://api.github.com/users/NJannasch) |
[Ouvill](https://api.github.com/users/Ouvill) |
[shorty2380](https://api.github.com/users/shorty2380) |
[Diadlo](https://api.github.com/users/Diadlo) |
[Cogitri](https://api.github.com/users/Cogitri) |
[metbril](https://api.github.com/users/metbril) |
[ruzaq](https://api.github.com/users/ruzaq) | +|
[kcrt](https://api.github.com/users/kcrt) |
[xissy](https://api.github.com/users/xissy) |
[Tekki](https://api.github.com/users/Tekki) |
[tbroadley](https://api.github.com/users/tbroadley) |
[Kriechi](https://api.github.com/users/Kriechi) |
[tkilaker](https://api.github.com/users/tkilaker) |
[tcyrus](https://api.github.com/users/tcyrus) | +|
[tobias-grasse](https://api.github.com/users/tobias-grasse) |
[strobeltobias](https://api.github.com/users/strobeltobias) |
[ymitsos](https://api.github.com/users/ymitsos) |
[cdorin93](https://api.github.com/users/cdorin93) |
[cybertramp](https://api.github.com/users/cybertramp) |
[delta-emil](https://api.github.com/users/delta-emil) |
[doc75](https://api.github.com/users/doc75) | +|
[ebayer](https://api.github.com/users/ebayer) |
[rasperepodvipodvert](https://api.github.com/users/rasperepodvipodvert) |
[hydrandt](https://api.github.com/users/hydrandt) |
[pensierocrea](https://api.github.com/users/pensierocrea) |
[rhtenhove](https://api.github.com/users/rhtenhove) |
[simonsan](https://api.github.com/users/simonsan) |
[tcassaert](https://api.github.com/users/tcassaert) | +|
[xcffl](https://api.github.com/users/xcffl) | | | | | | | + + # Known bugs - Resources larger than 10 MB are not currently supported on mobile. They will crash the application so it is recommended not to attach such resources at the moment. The issue is being looked at. diff --git a/Tools/build-translation.js b/Tools/build-translation.js index d62f6accb5..5fc66f271f 100644 --- a/Tools/build-translation.js +++ b/Tools/build-translation.js @@ -22,7 +22,7 @@ const cliLocalesDir = cliDir + '/locales'; const rnDir = rootDir + '/ReactNativeClient'; const electronDir = rootDir + '/ElectronClient/app'; -const { execCommand, isMac } = require('./tool-utils.js'); +const { execCommand, isMac, insertContentIntoFile } = require('./tool-utils.js'); const { countryDisplayName, countryCodeOnly } = require('lib/locale.js'); function parsePoFile(filePath) { @@ -203,16 +203,12 @@ function translationStatusToMdTable(status) { } async function updateReadmeWithStats(stats) { - const mdTableMarkerOpen = '\n'; - const mdTableMarkerClose = '\n'; - let mdTable = translationStatusToMdTable(stats); - mdTable = mdTableMarkerOpen + mdTable + mdTableMarkerClose; - - let content = await fs.readFile(rootDir + '/README.md', 'utf-8'); - // [^]* matches any character including new lines - const regex = new RegExp(mdTableMarkerOpen + '[^]*?' + mdTableMarkerClose); - content = content.replace(regex, mdTable); - await fs.writeFile(rootDir + '/README.md', content); + await insertContentIntoFile( + rootDir + '/README.md', + '\n', + '\n', + translationStatusToMdTable(stats) + ); } async function main() { diff --git a/Tools/package-lock.json b/Tools/package-lock.json index d0a86ceb08..4349687c7a 100644 --- a/Tools/package-lock.json +++ b/Tools/package-lock.json @@ -75,6 +75,15 @@ "hoek": "4.x.x" } }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, "camelcase": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", @@ -85,6 +94,14 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "clean-css": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "requires": { + "source-map": "~0.6.0" + } + }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -113,6 +130,11 @@ "delayed-stream": "~1.0.0" } }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -323,11 +345,30 @@ "sntp": "2.x.x" } }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, "hoek": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" }, + "html-minifier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", + "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", + "requires": { + "camel-case": "^3.0.0", + "clean-css": "^4.2.1", + "commander": "^2.19.0", + "he": "^1.2.0", + "param-case": "^2.1.1", + "relateurl": "^0.2.7", + "uglify-js": "^3.5.1" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -438,6 +479,11 @@ "path-exists": "^3.0.0" } }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" + }, "map-age-cleaner": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", @@ -501,6 +547,14 @@ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "requires": { + "lower-case": "^1.1.1" + } + }, "node-fetch": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", @@ -558,7 +612,7 @@ }, "p-is-promise": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=" }, "p-limit": { @@ -582,6 +636,14 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==" }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "requires": { + "no-case": "^2.2.0" + } + }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -621,6 +683,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" + }, "request": { "version": "2.85.0", "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", @@ -701,6 +768,11 @@ "hoek": "4.x.x" } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -780,11 +852,25 @@ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz", "integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg==" }, + "uglify-js": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "requires": { + "commander": "~2.20.0", + "source-map": "~0.6.1" + } + }, "universalify": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + }, "uri-template": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/uri-template/-/uri-template-1.0.1.tgz", @@ -823,7 +909,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", @@ -855,7 +941,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" diff --git a/Tools/package.json b/Tools/package.json index e36fe87196..b880275860 100644 --- a/Tools/package.json +++ b/Tools/package.json @@ -12,6 +12,7 @@ "app-module-path": "^2.2.0", "fs-extra": "^4.0.3", "gettext-parser": "^1.3.0", + "html-minifier": "^4.0.0", "markdown-it": "^8.4.1", "mustache": "^2.3.0", "node-fetch": "^1.7.3", diff --git a/Tools/tool-utils.js b/Tools/tool-utils.js index 6b5ca22ca0..f0425b858d 100644 --- a/Tools/tool-utils.js +++ b/Tools/tool-utils.js @@ -151,4 +151,13 @@ toolUtils.isMac = () => { return process && process.platform === 'darwin'; } +toolUtils.insertContentIntoFile = async function (filePath, markerOpen, markerClose, contentToInsert) { + const fs = require('fs-extra'); + let content = await fs.readFile(filePath, 'utf-8'); + // [^]* matches any character including new lines + const regex = new RegExp(markerOpen + '[^]*?' + markerClose); + content = content.replace(regex, markerOpen + contentToInsert + markerClose); + await fs.writeFile(filePath, content); +} + module.exports = toolUtils; \ No newline at end of file diff --git a/Tools/update-readme-contributors.js b/Tools/update-readme-contributors.js new file mode 100644 index 0000000000..f0d54c1197 --- /dev/null +++ b/Tools/update-readme-contributors.js @@ -0,0 +1,108 @@ +require('app-module-path').addPath(__dirname + '/../ReactNativeClient'); + +'use strict'; + +const fs = require('fs-extra'); +const https = require('https'); +const request = require('request'); + +const { fileExtension } = require('lib/path-utils.js'); +const readmePath = __dirname + '/../README.md'; +const { insertContentIntoFile } = require('./tool-utils.js'); +const markdownUtils = require('lib/markdownUtils'); + +async function gitHubContributors(page) { + return new Promise((resolve, reject) => { + request.get({ + url: 'https://api.github.com/repos/laurent22/joplin/contributors' + (page ? '?page=' + page : ''), + json: true, + headers: {'User-Agent': 'Joplin Readme Updater'} + }, (error, response, data) => { + if (error) { + reject(error); + } else if (response.statusCode !== 200) { + reject(new Error('Error HTTP ' + response.statusCode)); + } else { + resolve(data); + } + }); + }); +} + +function contributorTable(contributors) { + let rows = []; + + let row = []; + rows.push(row); + let x = 0; + let y = 0; + let rowLength = 7; + let contributorIndex = 0; + while (contributorIndex < contributors.length) { + const c = contributors[contributorIndex]; + contributorIndex++; + + const cell = `
[${c.login}](${c.url})`; + + row.push(cell); + + if (row.length >= rowLength) { + row = []; + rows.push(row); + } + } + + while (rows[rows.length - 1].length < rowLength) rows[rows.length - 1].push(''); + + const header = []; + const headerLine = []; + for (let i = 0; i < rowLength; i++) { + header.push(' '); + headerLine.push(':---:'); + } + + const lines = []; + lines.push('| ' + header.join(' | ') + ' |'); + lines.push('| ' + headerLine.join(' | ') + ' |'); + + for (const row of rows) { + lines.push('| ' + row.join(' | ') + ' |'); + } + + return lines.join('\n'); +} + +async function main(argv) { + let contributors = []; + let pageIndex = 0; + const doneNames = []; + while (true) { + const response = await gitHubContributors(pageIndex); + pageIndex++; + if (!response.length) break; + + // Remove duplicates + const temp = []; + for (const r of response) { + if (doneNames.indexOf(r.login) >= 0) continue; + doneNames.push(r.login); + temp.push(r); + } + + contributors = contributors.concat(temp); + } + + const tableHtml = contributorTable(contributors); + + await insertContentIntoFile( + readmePath, + '\n', + '\n', + tableHtml + ); +} + +main(process.argv).catch((error) => { + console.error('Fatal error', error); + process.exit(1); +}); \ No newline at end of file From f34330f1013392e96256d2763e7d9cace1880ecd Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Thu, 18 Jul 2019 20:46:01 +0100 Subject: [PATCH 07/10] Doc: Contributor list on rows of 5 --- README.md | 39 ++++++++++++++++------------- Tools/update-readme-contributors.js | 2 +- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 8c35ac3727..3ba88203e9 100644 --- a/README.md +++ b/README.md @@ -404,23 +404,28 @@ Current translations: # Contributors -| | | | | | | | -| :---: | :---: | :---: | :---: | :---: | :---: | :---: | -|
[laurent22](https://api.github.com/users/laurent22) |
[tessus](https://api.github.com/users/tessus) |
[CalebJohn](https://api.github.com/users/CalebJohn) |
[tanrax](https://api.github.com/users/tanrax) |
[rtmkrlv](https://api.github.com/users/rtmkrlv) |
[fmrtn](https://api.github.com/users/fmrtn) |
[gabcoh](https://api.github.com/users/gabcoh) | -|
[Abijeet](https://api.github.com/users/Abijeet) |
[innocuo](https://api.github.com/users/innocuo) |
[matsest](https://api.github.com/users/matsest) |
[marcosvega91](https://api.github.com/users/marcosvega91) |
[petrz12](https://api.github.com/users/petrz12) |
[foxmask](https://api.github.com/users/foxmask) |
[alexdevero](https://api.github.com/users/alexdevero) | -|
[moltenform](https://api.github.com/users/moltenform) |
[zuphilip](https://api.github.com/users/zuphilip) |
[abonte](https://api.github.com/users/abonte) |
[0ndrey](https://api.github.com/users/0ndrey) |
[stweil](https://api.github.com/users/stweil) |
[bradmcl](https://api.github.com/users/bradmcl) |
[RaphaelKimmig](https://api.github.com/users/RaphaelKimmig) | -|
[RenatoXSR](https://api.github.com/users/RenatoXSR) |
[sensor-freak](https://api.github.com/users/sensor-freak) |
[zblesk](https://api.github.com/users/zblesk) |
[chrisb86](https://api.github.com/users/chrisb86) |
[solariz](https://api.github.com/users/solariz) |
[mmahmoudian](https://api.github.com/users/mmahmoudian) |
[maicki](https://api.github.com/users/maicki) | -|
[mjjzf](https://api.github.com/users/mjjzf) |
[sebastienjust](https://api.github.com/users/sebastienjust) |
[Zorbeyd](https://api.github.com/users/Zorbeyd) |
[chenlhlinux](https://api.github.com/users/chenlhlinux) |
[pf-siedler](https://api.github.com/users/pf-siedler) |
[ruuti](https://api.github.com/users/ruuti) |
[s1nceri7y](https://api.github.com/users/s1nceri7y) | -|
[tfinnberg](https://api.github.com/users/tfinnberg) |
[ShuiHuo](https://api.github.com/users/ShuiHuo) |
[ikunya](https://api.github.com/users/ikunya) |
[Shaxine](https://api.github.com/users/Shaxine) |
[bimlas](https://api.github.com/users/bimlas) |
[chaifeng](https://api.github.com/users/chaifeng) |
[charles-e](https://api.github.com/users/charles-e) | -|
[chrmoritz](https://api.github.com/users/chrmoritz) |
[donbowman](https://api.github.com/users/donbowman) |
[dflock](https://api.github.com/users/dflock) |
[einverne](https://api.github.com/users/einverne) |
[Atalanttore](https://api.github.com/users/Atalanttore) |
[eodeluga](https://api.github.com/users/eodeluga) |
[FleischKarussel](https://api.github.com/users/FleischKarussel) | -|
[gmag11](https://api.github.com/users/gmag11) |
[gusbemacbe](https://api.github.com/users/gusbemacbe) |
[Fvbor](https://api.github.com/users/Fvbor) |
[sczhg](https://api.github.com/users/sczhg) |
[Vistaus](https://api.github.com/users/Vistaus) |
[jacobherrington](https://api.github.com/users/jacobherrington) |
[jcgerhard](https://api.github.com/users/jcgerhard) | -|
[jaredcrowe](https://api.github.com/users/jaredcrowe) |
[jmontane](https://api.github.com/users/jmontane) |
[JoelRSimpson](https://api.github.com/users/JoelRSimpson) |
[jony0008](https://api.github.com/users/jony0008) |
[joybinchen](https://api.github.com/users/joybinchen) |
[y-usuzumi](https://api.github.com/users/y-usuzumi) |
[xuhcc](https://api.github.com/users/xuhcc) | -|
[kklas](https://api.github.com/users/kklas) |
[lboullo0](https://api.github.com/users/lboullo0) |
[dbinary](https://api.github.com/users/dbinary) |
[mvonmaltitz](https://api.github.com/users/mvonmaltitz) |
[Marmo](https://api.github.com/users/Marmo) |
[mgroth0](https://api.github.com/users/mgroth0) |
[MichipX](https://api.github.com/users/MichipX) | -|
[NJannasch](https://api.github.com/users/NJannasch) |
[Ouvill](https://api.github.com/users/Ouvill) |
[shorty2380](https://api.github.com/users/shorty2380) |
[Diadlo](https://api.github.com/users/Diadlo) |
[Cogitri](https://api.github.com/users/Cogitri) |
[metbril](https://api.github.com/users/metbril) |
[ruzaq](https://api.github.com/users/ruzaq) | -|
[kcrt](https://api.github.com/users/kcrt) |
[xissy](https://api.github.com/users/xissy) |
[Tekki](https://api.github.com/users/Tekki) |
[tbroadley](https://api.github.com/users/tbroadley) |
[Kriechi](https://api.github.com/users/Kriechi) |
[tkilaker](https://api.github.com/users/tkilaker) |
[tcyrus](https://api.github.com/users/tcyrus) | -|
[tobias-grasse](https://api.github.com/users/tobias-grasse) |
[strobeltobias](https://api.github.com/users/strobeltobias) |
[ymitsos](https://api.github.com/users/ymitsos) |
[cdorin93](https://api.github.com/users/cdorin93) |
[cybertramp](https://api.github.com/users/cybertramp) |
[delta-emil](https://api.github.com/users/delta-emil) |
[doc75](https://api.github.com/users/doc75) | -|
[ebayer](https://api.github.com/users/ebayer) |
[rasperepodvipodvert](https://api.github.com/users/rasperepodvipodvert) |
[hydrandt](https://api.github.com/users/hydrandt) |
[pensierocrea](https://api.github.com/users/pensierocrea) |
[rhtenhove](https://api.github.com/users/rhtenhove) |
[simonsan](https://api.github.com/users/simonsan) |
[tcassaert](https://api.github.com/users/tcassaert) | -|
[xcffl](https://api.github.com/users/xcffl) | | | | | | | +| | | | | | +| :---: | :---: | :---: | :---: | :---: | +|
[laurent22](https://api.github.com/users/laurent22) |
[tessus](https://api.github.com/users/tessus) |
[CalebJohn](https://api.github.com/users/CalebJohn) |
[tanrax](https://api.github.com/users/tanrax) |
[rtmkrlv](https://api.github.com/users/rtmkrlv) | +|
[fmrtn](https://api.github.com/users/fmrtn) |
[gabcoh](https://api.github.com/users/gabcoh) |
[Abijeet](https://api.github.com/users/Abijeet) |
[innocuo](https://api.github.com/users/innocuo) |
[matsest](https://api.github.com/users/matsest) | +|
[marcosvega91](https://api.github.com/users/marcosvega91) |
[petrz12](https://api.github.com/users/petrz12) |
[foxmask](https://api.github.com/users/foxmask) |
[alexdevero](https://api.github.com/users/alexdevero) |
[moltenform](https://api.github.com/users/moltenform) | +|
[zuphilip](https://api.github.com/users/zuphilip) |
[abonte](https://api.github.com/users/abonte) |
[0ndrey](https://api.github.com/users/0ndrey) |
[stweil](https://api.github.com/users/stweil) |
[bradmcl](https://api.github.com/users/bradmcl) | +|
[RaphaelKimmig](https://api.github.com/users/RaphaelKimmig) |
[RenatoXSR](https://api.github.com/users/RenatoXSR) |
[sensor-freak](https://api.github.com/users/sensor-freak) |
[zblesk](https://api.github.com/users/zblesk) |
[chrisb86](https://api.github.com/users/chrisb86) | +|
[solariz](https://api.github.com/users/solariz) |
[mmahmoudian](https://api.github.com/users/mmahmoudian) |
[maicki](https://api.github.com/users/maicki) |
[mjjzf](https://api.github.com/users/mjjzf) |
[sebastienjust](https://api.github.com/users/sebastienjust) | +|
[Zorbeyd](https://api.github.com/users/Zorbeyd) |
[chenlhlinux](https://api.github.com/users/chenlhlinux) |
[pf-siedler](https://api.github.com/users/pf-siedler) |
[ruuti](https://api.github.com/users/ruuti) |
[s1nceri7y](https://api.github.com/users/s1nceri7y) | +|
[tfinnberg](https://api.github.com/users/tfinnberg) |
[ShuiHuo](https://api.github.com/users/ShuiHuo) |
[ikunya](https://api.github.com/users/ikunya) |
[Shaxine](https://api.github.com/users/Shaxine) |
[bimlas](https://api.github.com/users/bimlas) | +|
[chaifeng](https://api.github.com/users/chaifeng) |
[charles-e](https://api.github.com/users/charles-e) |
[chrmoritz](https://api.github.com/users/chrmoritz) |
[donbowman](https://api.github.com/users/donbowman) |
[dflock](https://api.github.com/users/dflock) | +|
[einverne](https://api.github.com/users/einverne) |
[Atalanttore](https://api.github.com/users/Atalanttore) |
[eodeluga](https://api.github.com/users/eodeluga) |
[FleischKarussel](https://api.github.com/users/FleischKarussel) |
[gmag11](https://api.github.com/users/gmag11) | +|
[gusbemacbe](https://api.github.com/users/gusbemacbe) |
[Fvbor](https://api.github.com/users/Fvbor) |
[sczhg](https://api.github.com/users/sczhg) |
[Vistaus](https://api.github.com/users/Vistaus) |
[jacobherrington](https://api.github.com/users/jacobherrington) | +|
[jcgerhard](https://api.github.com/users/jcgerhard) |
[jaredcrowe](https://api.github.com/users/jaredcrowe) |
[jmontane](https://api.github.com/users/jmontane) |
[JoelRSimpson](https://api.github.com/users/JoelRSimpson) |
[jony0008](https://api.github.com/users/jony0008) | +|
[joybinchen](https://api.github.com/users/joybinchen) |
[y-usuzumi](https://api.github.com/users/y-usuzumi) |
[xuhcc](https://api.github.com/users/xuhcc) |
[kklas](https://api.github.com/users/kklas) |
[lboullo0](https://api.github.com/users/lboullo0) | +|
[dbinary](https://api.github.com/users/dbinary) |
[mvonmaltitz](https://api.github.com/users/mvonmaltitz) |
[Marmo](https://api.github.com/users/Marmo) |
[mgroth0](https://api.github.com/users/mgroth0) |
[MichipX](https://api.github.com/users/MichipX) | +|
[NJannasch](https://api.github.com/users/NJannasch) |
[Ouvill](https://api.github.com/users/Ouvill) |
[shorty2380](https://api.github.com/users/shorty2380) |
[Diadlo](https://api.github.com/users/Diadlo) |
[Cogitri](https://api.github.com/users/Cogitri) | +|
[metbril](https://api.github.com/users/metbril) |
[ruzaq](https://api.github.com/users/ruzaq) |
[kcrt](https://api.github.com/users/kcrt) |
[xissy](https://api.github.com/users/xissy) |
[Tekki](https://api.github.com/users/Tekki) | +|
[tbroadley](https://api.github.com/users/tbroadley) |
[Kriechi](https://api.github.com/users/Kriechi) |
[tkilaker](https://api.github.com/users/tkilaker) |
[tcyrus](https://api.github.com/users/tcyrus) |
[tobias-grasse](https://api.github.com/users/tobias-grasse) | +|
[strobeltobias](https://api.github.com/users/strobeltobias) |
[ymitsos](https://api.github.com/users/ymitsos) |
[cdorin93](https://api.github.com/users/cdorin93) |
[cybertramp](https://api.github.com/users/cybertramp) |
[delta-emil](https://api.github.com/users/delta-emil) | +|
[doc75](https://api.github.com/users/doc75) |
[ebayer](https://api.github.com/users/ebayer) |
[rasperepodvipodvert](https://api.github.com/users/rasperepodvipodvert) |
[hydrandt](https://api.github.com/users/hydrandt) |
[pensierocrea](https://api.github.com/users/pensierocrea) | +|
[rhtenhove](https://api.github.com/users/rhtenhove) |
[simonsan](https://api.github.com/users/simonsan) |
[tcassaert](https://api.github.com/users/tcassaert) |
[xcffl](https://api.github.com/users/xcffl) | | # Known bugs diff --git a/Tools/update-readme-contributors.js b/Tools/update-readme-contributors.js index f0d54c1197..099e106dda 100644 --- a/Tools/update-readme-contributors.js +++ b/Tools/update-readme-contributors.js @@ -36,7 +36,7 @@ function contributorTable(contributors) { rows.push(row); let x = 0; let y = 0; - let rowLength = 7; + let rowLength = 5; let contributorIndex = 0; while (contributorIndex < contributors.length) { const c = contributors[contributorIndex]; From e29fb3eb6677b477c1eba926bf85cc85a110f0e0 Mon Sep 17 00:00:00 2001 From: "Helmut K. C. Tessarek" Date: Fri, 19 Jul 2019 15:01:32 -0400 Subject: [PATCH 08/10] new issue templates --- .github/ISSUE_TEMPLATE.md | 4 +++ .github/ISSUE_TEMPLATE/bug_report.md | 43 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 33 +++++++++++++++++ .github/ISSUE_TEMPLATE/question.md | 29 +++++++++++++++ {docs => .github}/PULL_REQUEST_TEMPLATE | 0 docs/issue_template.md | 26 -------------- 6 files changed, 109 insertions(+), 26 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/question.md rename {docs => .github}/PULL_REQUEST_TEMPLATE (100%) delete mode 100644 docs/issue_template.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..e3418051fd --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,4 @@ +👉 Please follow one of these issue templates: +- https://github.com/laurent22/joplin/issues/new/choose + +Note: to keep the backlog clean and actionable, issues may be immediately closed if they do not follow one of the above issue templates. diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..0df67c731b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,43 @@ +--- +name: "🐛 Bug Report" +about: Report a reproducible bug or regression in Joplin. +title: '' +labels: 'bug' + +--- + + + +## Environment + +Joplin version: +Platform: +OS specifcs: + + +## Steps To Reproduce + +1. +2. + + + +Describe what you expected to happen: + + + +## Logfile + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..17a04a9cfe --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,33 @@ +--- +name: Feature request +about: Suggest a feature for Joplin. +title: '[Feature request] ' +labels: 'feature request' + +--- + + + +## Has it been discussed in the forum? Link to topic. + + + +## Is your feature request related to a problem? Please describe. + + + +## Describe the solution you'd like + + + +## Describe alternatives you've considered + + + +## Additional context + diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000000..4cf79401e6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,29 @@ +--- +name: "🤔 Questions and Help" +about: The issue tracker is not for questions. Please ask questions on https://discourse.joplinapp.org/. +title: 'Question: ' +labels: 'question' + +--- + +🚨 The issue tracker is not for questions. 🚨 + +As it happens, support requests that are created as issues are likely to be closed. We want to make sure you are able to find the help you seek. + +## Questions and Help + +Please read the [documentation](https://joplinapp.org/) and [FAQ](https://joplinapp.org/faq/) first. + +### https://discourse.joplinapp.org/ + +If you have still questions related to Joplin, please open a topic in the [forum](https://discourse.joplinapp.org/). +You can use your GitHub credentials to login to the forum. + +## Links + +- Documentation: https://joplinapp.org +- FAQ: https://joplinapp.org/faq/ +- Forum: https://discourse.joplinapp.org +- How to enable end-to-end encryption: https://joplinapp.org/e2ee/ +- API documentation: https://joplinapp.org/api/ +- How to enable debug mode: https://joplinapp.org/debugging/ diff --git a/docs/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE similarity index 100% rename from docs/PULL_REQUEST_TEMPLATE rename to .github/PULL_REQUEST_TEMPLATE diff --git a/docs/issue_template.md b/docs/issue_template.md deleted file mode 100644 index a1018172cd..0000000000 --- a/docs/issue_template.md +++ /dev/null @@ -1,26 +0,0 @@ -### Operating system - - - -- Windows -- macOS -- Linux -- Android -- iOS - -### Application - - - -- Desktop -- Mobile -- Terminal - - From cd5d412c69f71650dd3b219a90c01902e6b3013c Mon Sep 17 00:00:00 2001 From: Caleb John Date: Sat, 20 Jul 2019 15:13:10 -0600 Subject: [PATCH 09/10] Desktop: Added support for templates (#1647) * First pass of adding support for templates * remove default value from template prompt * Add template placeholder text * Add mustache templates with datetime support for new notes * Moved template code to utils, added separate prompt for templates * Add templates to menu and allow for keyboad only use * update template prompt for dark theme * update with laurents suggestions, add refresh button * revert template command, remove new note prompt --- ElectronClient/app/app.js | 81 ++++++++++++++++++++++-- ElectronClient/app/gui/MainScreen.jsx | 28 +++++++- ElectronClient/app/gui/NoteText.jsx | 14 +++- ElectronClient/app/gui/PromptDialog.jsx | 49 +++++++++++--- ElectronClient/app/package-lock.json | 5 ++ ElectronClient/app/package.json | 1 + ElectronClient/app/style.css | 14 +++- README.md | 19 ++++++ ReactNativeClient/lib/BaseApplication.js | 1 + ReactNativeClient/lib/TemplateUtils.js | 59 +++++++++++++++++ ReactNativeClient/lib/models/Setting.js | 1 + ReactNativeClient/lib/reducer.js | 7 ++ 12 files changed, 263 insertions(+), 16 deletions(-) create mode 100644 ReactNativeClient/lib/TemplateUtils.js diff --git a/ElectronClient/app/app.js b/ElectronClient/app/app.js index 38714e4435..d93b3fd66f 100644 --- a/ElectronClient/app/app.js +++ b/ElectronClient/app/app.js @@ -26,11 +26,13 @@ const ResourceService = require('lib/services/ResourceService'); const ClipperServer = require('lib/ClipperServer'); const ExternalEditWatcher = require('lib/services/ExternalEditWatcher'); const { bridge } = require('electron').remote.require('./bridge'); +const { shell } = require('electron'); const Menu = bridge().Menu; const MenuItem = bridge().MenuItem; const PluginManager = require('lib/services/PluginManager'); const RevisionService = require('lib/services/RevisionService'); const MigrationService = require('lib/services/MigrationService'); +const TemplateUtils = require('lib/TemplateUtils'); const pluginClasses = [ require('./plugins/GotoAnything.min'), @@ -209,7 +211,7 @@ class Application extends BaseApplication { // The bridge runs within the main process, with its own instance of locale.js // so it needs to be set too here. bridge().setLocale(Setting.value('locale')); - this.refreshMenu(); + await this.refreshMenu(); } if (action.type == 'SETTING_UPDATE_ONE' && action.key == 'showTrayIcon' || action.type == 'SETTING_UPDATE_ALL') { @@ -246,10 +248,10 @@ class Application extends BaseApplication { return result; } - refreshMenu() { + async refreshMenu() { const screen = this.lastMenuScreen_; this.lastMenuScreen_ = null; - this.updateMenu(screen); + await this.updateMenu(screen); } focusElement_(target) { @@ -260,7 +262,7 @@ class Application extends BaseApplication { }); } - updateMenu(screen) { + async updateMenu(screen) { if (this.lastMenuScreen_ === screen) return; const sortNoteFolderItems = (type) => { @@ -328,6 +330,7 @@ class Application extends BaseApplication { const exportItems = []; const preferencesItems = []; const toolsItemsFirst = []; + const templateItems = []; const ioService = new InteropService(); const ioModules = ioService.modules(); for (let i = 0; i < ioModules.length; i++) { @@ -504,6 +507,57 @@ class Application extends BaseApplication { screens: ['Main'], }); + const templateDirExists = await shim.fsDriver().exists(Setting.value('templateDir')); + + templateItems.push({ + label: _('Create note from template'), + visible: templateDirExists, + click: () => { + this.dispatch({ + type: 'WINDOW_COMMAND', + name: 'selectTemplate', + noteType: 'note', + }); + } + }, { + label: _('Create to-do from template'), + visible: templateDirExists, + click: () => { + this.dispatch({ + type: 'WINDOW_COMMAND', + name: 'selectTemplate', + noteType: 'todo', + }); + } + }, { + label: _('Insert template'), + visible: templateDirExists, + accelerator: 'CommandOrControl+Alt+I', + click: () => { + this.dispatch({ + type: 'WINDOW_COMMAND', + name: 'selectTemplate', + }); + } + }, { + label: _('Open template directory'), + click: () => { + const templateDir = Setting.value('templateDir'); + if (!templateDirExists) shim.fsDriver().mkdir(templateDir); + shell.openItem(templateDir); + } + }, { + label: _('Refresh templates'), + click: async () => { + const templates = await TemplateUtils.loadTemplates(Setting.value('templateDir')); + + this.store().dispatch({ + type: 'TEMPLATE_UPDATE_ALL', + templates: templates + }); + } + }); + const toolsItems = toolsItemsFirst.concat(preferencesItems); function _checkForUpdates(ctx) { @@ -563,6 +617,13 @@ class Application extends BaseApplication { shim.isMac() ? noItem : newNotebookItem, { type: 'separator', visible: shim.isMac() ? false : true + }, { + label: _('Templates'), + visible: shim.isMac() ? false : true, + submenu: templateItems, + }, { + type: 'separator', + visible: shim.isMac() ? false : true }, { label: _('Import'), visible: shim.isMac() ? false : true, @@ -613,6 +674,11 @@ class Application extends BaseApplication { platforms: ['darwin'], accelerator: 'Command+W', selector: 'performClose:', + }, { + type: 'separator', + }, { + label: _('Templates'), + submenu: templateItems, }, { type: 'separator', }, { @@ -1080,6 +1146,13 @@ class Application extends BaseApplication { css: cssString }); + const templates = await TemplateUtils.loadTemplates(Setting.value('templateDir')); + + this.store().dispatch({ + type: 'TEMPLATE_UPDATE_ALL', + templates: templates + }); + // Note: Auto-update currently doesn't work in Linux: it downloads the update // but then doesn't install it on exit. if (shim.isWindows() || shim.isMac()) { diff --git a/ElectronClient/app/gui/MainScreen.jsx b/ElectronClient/app/gui/MainScreen.jsx index a123a038eb..e6a812e1f2 100644 --- a/ElectronClient/app/gui/MainScreen.jsx +++ b/ElectronClient/app/gui/MainScreen.jsx @@ -74,12 +74,13 @@ class MainScreenComponent extends React.Component { async doCommand(command) { if (!command) return; - const createNewNote = async (title, isTodo) => { + const createNewNote = async (template, isTodo) => { const folderId = Setting.value('activeFolderId'); if (!folderId) return; const newNote = { parent_id: folderId, + template: template, is_todo: isTodo ? 1 : 0, }; @@ -272,6 +273,30 @@ class MainScreenComponent extends React.Component { eventManager.emit('alarmChange', { noteId: note.id }); } + this.setState({ promptOptions: null }); + } + }, + }); + } else if (command.name === 'selectTemplate') { + this.setState({ + promptOptions: { + label: _('Template file:'), + inputType: 'dropdown', + value: this.props.templates[0], // Need to start with some value + autocomplete: this.props.templates, + onClose: async (answer) => { + if (answer) { + if (command.noteType === 'note' || command.noteType === 'todo') { + createNewNote(answer.value, command.noteType === 'todo'); + } else { + this.props.dispatch({ + type: 'WINDOW_COMMAND', + name: 'insertTemplate', + value: answer.value, + }); + } + } + this.setState({ promptOptions: null }); } }, @@ -523,6 +548,7 @@ const mapStateToProps = (state) => { selectedNoteId: state.selectedNoteIds.length === 1 ? state.selectedNoteIds[0] : null, plugins: state.plugins, noteDevToolsVisible: state.noteDevToolsVisible, + templates: state.templates, }; }; diff --git a/ElectronClient/app/gui/NoteText.jsx b/ElectronClient/app/gui/NoteText.jsx index c5f61b07b1..437fd18202 100644 --- a/ElectronClient/app/gui/NoteText.jsx +++ b/ElectronClient/app/gui/NoteText.jsx @@ -40,6 +40,7 @@ const DecryptionWorker = require('lib/services/DecryptionWorker'); const ModelCache = require('lib/services/ModelCache'); const NoteTextViewer = require('./NoteTextViewer.min'); const NoteRevisionViewer = require('./NoteRevisionViewer.min'); +const TemplateUtils = require('lib/TemplateUtils'); require('brace/mode/markdown'); // https://ace.c9.io/build/kitchen-sink.html @@ -452,14 +453,18 @@ class NoteTextComponent extends React.Component { const stateNoteId = this.state.note ? this.state.note.id : null; let noteId = null; let note = null; + let newNote = null; let loadingNewNote = true; let parentFolder = null; let noteTags = []; let scrollPercent = 0; if (props.newNote) { - note = Object.assign({}, props.newNote); + // assign new note and prevent body from being null + note = Object.assign({}, props.newNote, {body: ''}); this.lastLoadedNoteId_ = null; + if (note.template) + note.body = TemplateUtils.render(note.template); } else { noteId = props.noteId; @@ -1012,6 +1017,8 @@ class NoteTextComponent extends React.Component { fn = this.commandShowLocalSearch; } else if (command.name === 'textCode') { fn = this.commandTextCode; + } else if (command.name === 'insertTemplate') { + fn = () => { return this.commandTemplate(command.value); }; } } @@ -1349,6 +1356,10 @@ class NoteTextComponent extends React.Component { this.wrapSelectionWithStrings('`', '`'); } + commandTemplate(value) { + this.wrapSelectionWithStrings(TemplateUtils.render(value)); + } + addListItem(string1, string2 = '', defaultText = '') { const currentLine = this.selectionRangeCurrentLine(); let newLine = '\n' @@ -1920,6 +1931,7 @@ const mapStateToProps = (state) => { customCss: state.customCss, lastEditorScrollPercents: state.lastEditorScrollPercents, historyNotes: state.historyNotes, + templates: state.templates, }; }; diff --git a/ElectronClient/app/gui/PromptDialog.jsx b/ElectronClient/app/gui/PromptDialog.jsx index 288ebf7bbf..17dbcca436 100644 --- a/ElectronClient/app/gui/PromptDialog.jsx +++ b/ElectronClient/app/gui/PromptDialog.jsx @@ -6,6 +6,7 @@ const { themeStyle } = require('../theme.js'); const { time } = require('lib/time-utils.js'); const Datetime = require('react-datetime'); const CreatableSelect = require('react-select/lib/Creatable').default; +const Select = require('react-select').default; const makeAnimated = require('react-select/lib/animated').default; class PromptDialog extends React.Component { @@ -101,7 +102,7 @@ class PromptDialog extends React.Component { borderColor: theme.dividerColor, }; - this.styles_.tagList = { + this.styles_.select = { control: (provided) => (Object.assign(provided, { minWidth: width * 0.2, maxWidth: width * 0.5, @@ -115,6 +116,10 @@ class PromptDialog extends React.Component { fontFamily: theme.fontFamily, backgroundColor: theme.backgroundColor, })), + option: (provided) => (Object.assign(provided, { + color: theme.color, + fontFamily: theme.fontFamily, + })), multiValueLabel: (provided) => (Object.assign(provided, { fontFamily: theme.fontFamily, })), @@ -123,14 +128,22 @@ class PromptDialog extends React.Component { })), }; - this.styles_.tagListTheme = (tagTheme) => (Object.assign(tagTheme, { + this.styles_.selectTheme = (tagTheme) => (Object.assign(tagTheme, { borderRadius: 2, colors: Object.assign(tagTheme.colors, { primary: theme.raisedBackgroundColor, primary25: theme.raisedBackgroundColor, neutral0: theme.backgroundColor, + neutral5: theme.backgroundColor, neutral10: theme.raisedBackgroundColor, + neutral20: theme.raisedBackgroundColor, + neutral30: theme.raisedBackgroundColor, + neutral40: theme.color, + neutral50: theme.color, + neutral60: theme.color, + neutral70: theme.color, neutral80: theme.color, + neutral90: theme.color, danger: theme.backgroundColor, dangerLight: theme.colorError2, }), @@ -179,14 +192,19 @@ class PromptDialog extends React.Component { this.setState({ answer: momentObject }); } - const onTagsChange = (newTags) => { - this.setState({ answer: newTags }); + const onSelectChange = (newValue) => { + this.setState({ answer: newValue }); this.focusInput_ = true; } const onKeyDown = (event) => { - if (event.key === 'Enter' && this.props.inputType !== 'tags') { - onClose(true); + if (event.key === 'Enter') { + if (this.props.inputType !== 'tags' && this.props.inputType !== 'dropdown') { + onClose(true); + } else if (this.answerInput_.current && !this.answerInput_.current.state.menuIsOpen) { + // The menu will be open if the user is selecting a new item + onClose(true); + } } else if (event.key === 'Escape') { onClose(false); } @@ -206,8 +224,8 @@ class PromptDialog extends React.Component { /> } else if (this.props.inputType === 'tags') { inputComp = onKeyDown(event)} + /> + } else if (this.props.inputType === 'dropdown') { + inputComp =