1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-08-27 20:29:45 +02:00

Compare commits

...

438 Commits

Author SHA1 Message Date
Laurent Cozic
8c1d13b364 Android release v1.0.312 2019-12-08 10:09:25 +00:00
Laurent Cozic
7ad407a8c8 Electron release v1.0.175 2019-12-08 10:04:35 +00:00
Laurent Cozic
bd02704384 Merge branch 'master' of github.com:laurent22/joplin 2019-12-08 10:01:04 +00:00
Laurent Cozic
03831babcd Update README.md 2019-12-06 09:44:03 +00:00
Laurent Cozic
cfe61bbb9b Merge branch 'master' of github.com:laurent22/joplin 2019-12-05 10:06:17 +00:00
Helmut K. C. Tessarek
a3bfb19059 update JoplinLetter.svg (#2154) 2019-12-05 09:45:12 +00:00
Helmut K. C. Tessarek
e5f116fd2d Clipper: update icons (#2152)
* update clipper icons

* change dev color to grey
2019-12-05 09:44:46 +00:00
Helmut K. C. Tessarek
a7f3a70ba4 Desktop: Better icon for about window (#2150) 2019-12-05 09:44:16 +00:00
Helmut K. C. Tessarek
1607a57fb7 macOS: Update icons (#2147)
+---------------------+--------------------+--------------+
|      filename       | resolution, pixels | density, PPI |
+---------------------+--------------------+--------------+
| icon_16x16.png      | 16x16              |           72 |
| icon_16x16@2x.png   | 32x32              |          144 |
| icon_32x32.png      | 32x32              |           72 |
| icon_32x32@2x.png   | 64x64              |          144 |
| icon_128x128.png    | 128x128            |           72 |
| icon_128x128@2x.png | 256x256            |          144 |
| icon_256x256.png    | 256x256            |           72 |
| icon_256x256@2x.png | 512x512            |          144 |
| icon_512x512.png    | 512x512            |           72 |
| icon_512x512@2x.png | 1024x1024          |          144 |
+---------------------+--------------------+--------------+
2019-12-05 09:43:22 +00:00
Laurent Cozic
ecd7690743 Tools: Adding TypeScript config 2019-12-04 21:06:22 +00:00
Laurent Cozic
47a2087a91 Updating icons 2019-12-04 19:01:08 +00:00
Laurent Cozic
7653764403 Doc: box.com no longer supports WebDAV 2019-12-04 00:00:02 +00:00
Laurent Cozic
b7c8d5b9b1 Android: Updated icon and converted it to new Adaptive Icon format 2019-12-03 17:28:32 +00:00
Laurent Cozic
fdac132905 Updating icons 2019-12-02 21:23:30 +00:00
Laurent Cozic
60b993412e Doc: Updated website icon and cleaned up design a bit 2019-12-02 20:41:26 +00:00
Laurent Cozic
697c914c77 Merge branch 'master' of github.com:laurent22/joplin 2019-12-03 15:52:01 +00:00
Devon Zuegel
8c17ecb3d9 Desktop: Add highlight_mark token to Ace editor rules (#2100)
* Added highlight_mark token to Ace editor rules

* Fix edge case for highlight_mark Ace rule

* Add ==mark== rule only if plugin is enabled

* Rm temporary highlight class
2019-12-03 11:12:47 +00:00
Laurent Cozic
4c93121102 Added GSoC 2020 banner 2019-12-02 10:55:45 +00:00
Helmut K. C. Tessarek
5efe9b99c2 fix missing double quotes in nb_NO.po 2019-12-01 20:26:10 -05:00
Mats Estensen
3249763091 Translation: Update nb_NO.po (#2135)
* Update norwegian

* fix typo
2019-12-01 20:15:42 -05:00
Laurent Cozic
60964a4224 Tools: Removed uneeded untranslatedCount prop from translation index 2019-11-29 18:51:55 +00:00
Laurent Cozic
805a5399b5 All: Fixes #2126: Restaured translations that had been accidentally deleted 2019-11-29 15:47:12 +00:00
Laurent Cozic
0a39e4ccb0 Merge branch 'master' of github.com:laurent22/joplin 2019-11-29 15:40:20 +00:00
Laurent Cozic
f8cb908e0f Tools: Added check on translation builder to prevent it from deleting too many translations 2019-11-28 18:27:38 +00:00
Laurent Cozic
d2aceed34e Security: Upgraded packages to fix security issues on clipper 2019-11-28 17:33:54 +00:00
Laurent Cozic
e6d9d83d92 Desktop: Fixes #1826: Fixed warning boxes in solarized theme 2019-11-28 17:09:52 +00:00
Laurent Cozic
1a1c87b5c4 Update Turkish translation (Thanks Hüseyin Fahri Uzun) 2019-11-27 11:02:30 +00:00
exprez135
5bcec583bb Finish translation of es_ES.po and standardize quotation marks format to guillemets (#2125) 2019-11-26 17:39:40 -05:00
Christiaan de Die le Clercq
692606292f Translation: Update nl_NL.po (#2123)
Noticed a small typo when using the application
2019-11-26 17:38:51 -05:00
Helmut K. C. Tessarek
1782e55c66 update the resource icon (for internal/local links) 2019-11-22 18:12:39 -05:00
Laurent Cozic
707828ca76 All: Fixes #2117: Prevent synch from happening if target dir could not be created, in local sync 2019-11-21 19:54:09 +00:00
Laurent Cozic
5b0a817d69 Update stale.yml 2019-11-21 09:31:24 +00:00
Laurent Cozic
23e77efc83 Android release v1.0.311 2019-11-20 20:57:25 +00:00
Laurent Cozic
03c7368d71 iOS v10.0.40 2019-11-20 20:48:37 +00:00
Laurent Cozic
fdc80f0663 Update translations 2019-11-20 19:06:45 +00:00
Laurent Cozic
4e708ea021 Doc: More GSoC 2019-11-20 19:01:01 +00:00
Laurent Cozic
49898d01b5 Doc: Added GSoC to website 2019-11-20 18:47:32 +00:00
Laurent Cozic
8036923aca All: Added more logging for resource fetching to try to debug issue 2019-11-20 18:47:18 +00:00
Dominik Bamberger
76c8f777ca Move variable declaration before its first use. (#2109)
* Move variable declaration before its first use.

* Remove trailing whitespace
2019-11-20 18:19:33 +00:00
Marcus Hill
e84bafd034 All: Resolves #2097: Add warning message when user tries to upload a file 10MB or larger (#2102) 2019-11-20 18:18:58 +00:00
PackElend
37fc42eb73 Doc: GsoC first public draft of documentation (#2092)
* GSoC root file

This is the root file for the Google Summer of Code program

* Fixed TOC

* Introduction to GSoC with Joplin

The first draft cloned from https://community.kde.org/GSoC

* Joplin's Application at GSoC template

Cloned from https://wiki.openstreetmap.org/wiki/Google_Summer_of_Code/2019/Organisation_application

* GSoC 2019, idea #1: deeper Nextcloud integration

* GSoC 2019, idea #2: sharing notes

* GSoC 2019, idea #2: tag handling

* GSoC 2019, idea #4: search improvements

* GSoC 2019, idea #5: per note password protection

* Update GSoC_Idea#1.md

* Update GSoC_Idea#2.md

* Rename GSoC_Idea#2.md to GSoC_Idea#2_sharing.md

* Rename GSoC_Idea#1.md to GSoC2019_Idea#1_Nextcloud.md

* Rename GSoC_Idea#2_sharing.md to GSoC2019_Idea#2_sharing.md

* Update and rename GSoC_Idea#3.md to GSoC2019_Idea#3_tagging.md

* Rename GSoC_Idea#4.md to GSoC2019_Idea#4_Search.md

* Rename GSoC_Idea#5.md to GSoC2019_Idea#5_Password per Note.md

* Update GSoC2019_Idea#1_Nextcloud.md

* Create GSoC2019.md

cloned from https://community.kde.org/GSoC/2019/Ideas

* Rename Introduction.md to GSoCIntroduction.md

* Rename GSoCIntroduction.md to GSoC_Introduction.md

* Rename Application.md to GSoC_Application.md

* first draft of a public introduction and project idea page, plus first (filled) template for ideas

* added idea

* started to update org details

* Delete GSoC_Application.md

moved to forum

* Update summer_of_code.md

put the template in a <details> block. little improvements where to publish ideas and applications

* Update summer_of_code.md

put application in quote
2019-11-20 18:17:51 +00:00
Laurent Cozic
a0a89112bd Merge branch 'master' of github.com:laurent22/joplin 2019-11-20 18:17:08 +00:00
Laurent Cozic
4842f83aae All: Fixes #2088: Handle rare case when notebook has a parent that no longer exists, which causes a crash when sorting 2019-11-20 18:14:11 +00:00
taw00
69b185ff5e Documentation: correct and expand the markdown instructions for a link (#2106)
* correcting and expanding the markdown instructions for a link
- "some content" in `[some content](https://somelink/)` is called the
    content of an entity (or alt text for an image link)
- "some title" in this example is the the title element of the
    entity: `[some content](https://somelink/ "some title")`

* link description: Fixed a typo, restructured a line break I screwed up, and I cleaned up the language a bit
2019-11-20 12:09:03 -05:00
vicoutorama
d8c2f0cbba Translation: Update pt_BR.po (#2116)
Done some updates to pt BR translation. Hope it helps!
2019-11-19 21:03:29 -05:00
genneko
5b05f22476 Translation: Update ja_JP.po (#2115) 2019-11-19 21:02:27 -05:00
rikanotank1
8012d1fcfc Translation: Update zh_CN.po (#2108)
Translated some theme part into chinese
2019-11-19 15:19:02 -05:00
Laurent Cozic
40753296c4 iOS: Fixes #2103: Fix issue when WebDAV server redirects certain API calls 2019-11-19 09:09:01 +00:00
Laurent Cozic
7baeb223f3 Update markdown.md 2019-11-18 10:26:07 +00:00
Laurent Cozic
affacf472f Doc: Fix Esperanto flag 2019-11-18 08:55:23 +00:00
Laurent Cozic
896925ca49 Doc: Added link on website to improve doc 2019-11-18 08:49:01 +00:00
Laurent Cozic
78628c0f42 Doc: Switching to Fork Awesome 2019-11-18 08:39:37 +00:00
Laurent Cozic
ee650c1ef4 Doc: Switching to Fork Awesome 2019-11-18 08:31:17 +00:00
Laurent Cozic
5b65fae49d All: Improved logging during sync to allow finding bugs more easily 2019-11-13 18:54:54 +00:00
barbowza
2d5d8ceb1d Desktop: Allow Electron debugging flag (#2084)
* Add check for Electron's cli arg --remote-debugging-port and discard it to prevent cli arg parser raising Unknown flag exception.

* Jump to next iteration once arg processed

* Allow only the strict form of flag as --x=y
2019-11-13 21:38:09 +00:00
Tomáš Bambas
de214c8695 Translation: update Czech cs_CZ.po (#2086) 2019-11-13 16:33:44 -05:00
Laurent Cozic
ca2446aef0 Update website 2019-11-12 18:21:28 +00:00
Laurent Cozic
0ca96ee8be Electron release v1.0.174 2019-11-12 17:56:59 +00:00
Laurent Cozic
0c82c108ec Update translations 2019-11-12 17:55:58 +00:00
Laurent Cozic
15f09ef169 Revert "Desktop: Stop watching external edits when closing editor (#1981)"
Due to this issue:

https://discourse.joplinapp.org/t/joplin-version-1-0-173/4232/7

This reverts commit 0eb51e6bb0.
2019-11-12 17:51:57 +00:00
Laurent Cozic
45cca9e002 Desktop: Fixes #2079: Do not crash when a notebook parent does not exist 2019-11-12 17:50:48 +00:00
Laurent Cozic
76ecfd0234 Merge branch 'master' of github.com:laurent22/joplin 2019-11-12 16:16:52 +00:00
Laurent Cozic
927d46b2e4 Fix tests 2019-11-12 16:16:39 +00:00
Caleb John
3353598041 Desktop, Mobile: Fix scaling of inline svg resource icons (#2075)
* Fix scaling of inline svg resource icons

* prevent link icons from repeating
2019-11-12 16:02:42 +00:00
Xaris Ar
e0b7cbd70b Update Greek Translation (#2080)
* Create el_GR.po (part1)

* Update el_GR.po

* Update el_GR.po (part 2)

* Update el_GR.po

* Finished Greek(el_GR) translation

Finished translating all texts.
Update el_GR.po (beta)

* Update el_GR.po

to meet requirements for Joplin 1.0.173

* Update locale.js
2019-11-12 16:01:56 +00:00
barbowza
21d06ad9a6 Tools: Optional open dev tools in Developer Mode (#2083)
* Require --open-dev-tools along with --env dev in command line options to make opening of Dev Tools optional when in Developer mode.

* Restore original lines then comment out the call to openDevTools
2019-11-12 16:00:44 +00:00
Helmut K. C. Tessarek
9e227200af Clipper release v1.0.19 2019-11-11 14:29:30 -05:00
Helmut K. C. Tessarek
bac546c090 CLI v1.0.150 2019-11-11 14:21:07 -05:00
Laurent Cozic
058b6265a6 Merge branch 'master' of github.com:laurent22/joplin 2019-11-11 09:43:42 +00:00
Laurent Cozic
d4234b8921 ios-v10.0.39 2019-11-11 09:43:24 +00:00
Laurent Cozic
18762cd4d5 Desktop: Show note count by default 2019-11-11 08:44:54 +00:00
Laurent Cozic
9a2a223650 Update website 2019-11-11 08:33:56 +00:00
Laurent Cozic
a0ad2b24b1 Electron release v1.0.173 2019-11-11 08:22:48 +00:00
Laurent Cozic
211c02c7de Disable test units when releasing version 2019-11-11 08:22:31 +00:00
Laurent Cozic
a3279ab164 Electron release v1.0.172 2019-11-11 07:59:29 +00:00
Laurent Cozic
d0ce79d81b Update website 2019-11-11 07:57:33 +00:00
Laurent Cozic
e896be48f0 Android release v1.0.310 2019-11-11 07:22:20 +00:00
Laurent Cozic
a806d753c4 Electron release v1.0.171 2019-11-11 07:16:33 +00:00
Helmut K. C. Tessarek
ab4fd9ed53 Update translations 2019-11-11 01:46:03 -05:00
Diego Erdody
9c98fb5312 Desktop: Add new setting to show note counts for folders and tags (#2006)
* Adding node counts for folders and tags

* Add unit tests

* Fix count update when the tag list for a note is updated

* Right align note counts and remove from the settings screen

* Folder note count calculation update to include descendants

* Update Setting.js

* Change count style and fix click on counts

* Fix tag/folder count update on delete/add note

* Review updates
2019-11-11 06:14:56 +00:00
Laurent Cozic
c0dd8d0332 Merge branch 'master' of github.com:laurent22/joplin 2019-11-07 22:38:36 +00:00
Laurent Cozic
60a1f96b4f Desktop, Mobile: Fixes #2030: Fix handling of URLs that contain single quotes 2019-11-07 22:38:22 +00:00
Helmut K. C. Tessarek
40dfb730dc we do not want localization for logging output
/ref https://discourse.joplinapp.org/t/message-in-log-file-translated-by-mistake/4198?u=tessus
2019-11-07 16:35:04 -05:00
Laurent Cozic
4e72a8f3a5 Clipper: Fixes #2034: Better handling of HTML minifying error with fallback to non-minified HTML 2019-11-07 20:32:11 +00:00
Laurent Cozic
3da32f007e Clipper: Fixes #2015: Fix issue with certain PRE code blocks 2019-11-07 20:06:33 +00:00
Laurent Cozic
4af8bb8e8d Clipper: Fixes #1990: Clipper was not saving page URL when taking screenshot 2019-11-07 18:12:14 +00:00
Laurent Cozic
a6f190766c Clipper: Upgrade packages to fix security issue 2019-11-07 18:10:19 +00:00
Shane Kilkelly
fa3f0d2071 Desktop: Resolves #1298: Add keyboard modes to editor (vim, emacs) (#2056)
* Add keyboard modes to editor (vim, emacs, default)

This adds a new option to settings, and then sets the
appropriate keyboard handler in the ace editor.

The "default" option is equivalent to the old keyboard
behaviour.

* Remove stray console.log

* Move the keyboard-mode setting to the general section

* Change `keyboardMode` setting to `editor.keyboardMode`
2019-11-06 21:51:08 +00:00
boring10
8d6cfdc292 Desktop: Fixes #1570: Prevent horizontal scrolling on Linux when a scrollbar is present in note list (#2062)
* Prevent horizontal scrolling on Linux when a scrollbar is present in the note list.

* max-width usage specifically to target Linux horizontal scroll problem.
2019-11-06 21:46:26 +00:00
Helmut K. C. Tessarek
48f0c1c37b All: Resolves #2042: Set user-agent header to Joplin/1.0 (#2064)
closes #2042
2019-11-06 09:54:16 +00:00
Christian Moritz
17584b52af CLI: update sharp tp v0.23.2 (for node 13 compatibility) (#2063) 2019-11-06 09:52:48 +00:00
Caleb John
c05bc899eb Desktop, Mobile: Added link resource icon (#2035)
* Add forkawesome icons

* Add resource icon for specific filetypes

* Ignore resource link styling on mobile

* whtiespace

* render txt icons and adjust icon sizes

* Replace fork-awesome font with inline svg so icons work on mobile

* Add comment describing the source of resource icons
2019-11-05 21:41:36 +00:00
Laurent Cozic
c9f6ce7496 Merge branch 'master' of github.com:laurent22/joplin 2019-11-05 17:16:43 +00:00
Laurent Cozic
67d2c454ee Desktop: Resolves #2031: Prevent window from being shown on startup when it should be hidden in tray 2019-11-05 17:03:24 +00:00
Helmut K. C. Tessarek
83c3c027d0 Desktop, Mobile: Fix TOC with special characters (#2052) 2019-11-05 13:18:05 +00:00
genneko
3cac187023 Translation: Update ja_JP.po (#2061) 2019-11-05 00:30:14 -05:00
Helmut K. C. Tessarek
3800b0bf47 Update de_DE.po 2019-11-04 19:07:56 -05:00
Helmut K. C. Tessarek
41b2eb8871 Update translations 2019-11-04 19:02:39 -05:00
Helmut K. C. Tessarek
bc84cdda7d Translation: pt_BR.po (#2060)
Translation: pt_BR.po
2019-11-04 18:47:51 -05:00
Marton Paulo
6d77394196 Translation: add Esperanto language (eo.po) (#2054)
* Add Esperanto language

* Update Esperanto language to 40% completed

* Update Esperanto language to 51% completed
2019-11-04 18:47:05 -05:00
Marton Paulo
968bba4d8e Updated Brazilian Portuguese language to 100% complete 2019-11-04 18:41:02 -05:00
Helmut K. C. Tessarek
cdd8090f33 Update de_DE.po 2019-11-04 15:40:43 -05:00
Helmut K. C. Tessarek
1be26e4497 Update web site 2019-11-02 09:47:19 -04:00
Laurent Cozic
cc51ba4f90 Tools: Upgraded jasmine and made it easier to filter tests 2019-11-02 10:19:24 +00:00
Laurent Cozic
85984109b5 Merge branch 'master' of github.com:laurent22/joplin 2019-11-01 22:44:50 +00:00
Laurent Cozic
689a12cdfb Cli: Fixes #2039: Handle paths with spaces for text editor 2019-11-01 22:42:05 +00:00
Laurent Cozic
abd74db112 Doc: Removed Hacktoberfest 🎃 banner 2019-11-01 13:20:35 +00:00
m-svo
cb06dab16f fix typo in install_and_update.sh (#2051) 2019-11-01 11:28:25 +00:00
Laurent Cozic
d2a7e46c1a Fix tests 2019-10-31 09:55:39 +00:00
Laurent Cozic
2997b0f2c4 Renamed 'layout' setting to 'layoutButtonSequence' 2019-10-31 08:47:45 +00:00
Subodh Dahal
f450ef09cc Desktop: Resolves #1900: Allow selecting what views should be available from the Layout button (#2028)
* Added options for selecting layout

* Toggle through the layouts based on config

* Used redux state for getting layout settings

* Removed duplicated strings for layout options

* Moved option for selecting layouts to "View" menu
2019-10-31 08:42:17 +00:00
aerotog
316746605e Desktop: Fixes #1790: Stop print command from resetting theme (#1999) 2019-10-31 08:33:40 +00:00
Laurent Cozic
5522d11eed Merge branch 'master' of github.com:laurent22/joplin 2019-10-31 07:25:39 +00:00
Helmut K. C. Tessarek
67266af1ae fix layout issue introduced by #1991 2019-10-30 16:59:32 -04:00
Laurent Cozic
273c0f432c Desktop: Fixed attachment markup when importing ENEX files as HTML so that it works in mobile too 2019-10-30 18:23:37 +00:00
Laurent Cozic
d346cdb897 Added Bosnian language and cleaned up translations 2019-10-30 18:12:06 +00:00
Fernando K
57a4b48c9b Desktop, Mobile: Resolves #2043: Add <kbd> tag support (#2044) 2019-10-30 15:43:58 +00:00
Daniel Landau
c3b1018929 Desktop: Resolves #215: Fill X primary selection from the editor on text selection (#2029)
This fixes the Joplin->"other apps" half of
https://github.com/laurent22/joplin/issues/215.
2019-10-30 15:40:59 +00:00
Laurent Cozic
a2ba64ccf5 Merge branch 'master' of github.com:laurent22/joplin 2019-10-30 13:56:59 +00:00
Helmut K. C. Tessarek
26d91e355a Mobile: Show alarm in correct date and time format (#2026) 2019-10-30 10:24:06 +00:00
Stephanie Foskitt
7bf394d8d5 Desktop: Resolves #1918: Allow custom CSS when printing (#2014)
* Sets `useCustomCss` default to "true".   Updates README.md for reference to Custom CSS.

* Reverse changes to  and .  Correct the spacing in .
2019-10-30 10:21:58 +00:00
Helmut K. C. Tessarek
cdf6f9c436 Desktop, Mobile: Resolves #1953: Update Markdown plugins: toc-done-right, anchor (#2005)
This change fixes a few issues with the toc plugin.
It now allows to set inline options. e.g. to set the max toc depth.

1. set toc depth to 2 levels

```
$<toc{"level":[1,2]}>
```

2. set toc depth to 3 levels and use an ordered list

```
$<toc{"level":[1,2,3],"listType":"ol"}>
```

/ref https://github.com/nagaozen/markdown-it-toc-done-right/issues/16

---

fixes #1953
fixes #1843
fixes https://discourse.joplinapp.org/t/set-depth-of-toc/2899
2019-10-30 10:18:31 +00:00
Helmut K. C. Tessarek
dece5d8de7 Desktop: Resolves #1903: Add Nord theme (#2004)
code by vzsky (PR was abandoned)
closes #1903
2019-10-30 09:55:45 +00:00
Laurent Cozic
33b8da98af Clean up 2019-10-30 09:54:32 +00:00
Hanna Bennett
0386534b3a CLI: Resolves #1974: Add command to list all tags for a note (#2003)
* Add command to list tags associated with a given note

* Update description

* Fix autocompletion to do notes instead of tags when tag-command is notetags
2019-10-30 09:43:47 +00:00
Tommy Bergeron
885858dcb4 Desktop: Resolves #1988: Add menu item to toggle note list (#1991)
* Add menu item to toggle note list #1988

* Hiding the noteList now fully works + standardized casing for noteList #1988

* hiding verticalResizer to fully hide note list and its extra border #1988

* curly braces on the same line #1988

* fa-tasks is "less" worse as an icon for toggle note list #1988

* liking this icon a whole lot more

* removed useless width tweak
2019-10-30 09:40:33 +00:00
Laurent Cozic
8c5d82fab2 Update CONTRIBUTING.md 2019-10-30 09:11:07 +00:00
Laurent Cozic
c683c1b8ec Doc: Added link to good-first-issue tag 2019-10-30 09:06:57 +00:00
Laurent Cozic
cde5aa9b06 Merge branch 'master' of github.com:laurent22/joplin 2019-10-29 11:08:48 +00:00
luzpaz
d3ba6798d7 Doc: Fix documentation and source comment typos (#2037)
* Misc. typo and whitespace fixes

Found via `codespell -q 3 -S *.po,*.pot,./ElectronClient/app/locales,./ReactNativeClient/locales,./CliClient/locales -L adresse,ba,fonction,te,whet`

* Revert a previous change
2019-10-29 09:02:42 +00:00
Helmut K. C. Tessarek
1f42c10c2a Update translations 2019-10-28 21:18:18 -04:00
exponentactivity
14f6108e57 Translation: update Danish (da_DK.po ) (#2033) 2019-10-28 21:00:43 -04:00
Helmut K. C. Tessarek
9512a08810 Update web site 2019-10-28 20:26:19 -04:00
Helmut K. C. Tessarek
78b8648945 add FAQ entry on how to restart Joplin on Windows 2019-10-28 20:22:45 -04:00
Laurent Cozic
71e01e5566 Cli: Handle special shortcuts such as Ctrl+H 2019-10-28 20:10:03 +00:00
Laurent Cozic
01614b5a13 All: Resolves #2002: Handle WebDAV server with empty XML namespaces 2019-10-28 19:15:18 +00:00
Laurent Cozic
7153c06e88 Api: Fixes #2018: Fixed error handling when getting resources of a note that does not exist 2019-10-28 19:02:29 +00:00
Laurent Cozic
30969f8ab6 Desktop: Fixes #1867: Fix scrolling issue when clicking on internal link 2019-10-28 18:56:38 +00:00
Laurent Cozic
19f9c4f540 Desktop: Fixes #2008: Open links in external browser from revision view 2019-10-28 18:47:23 +00:00
Laurent Cozic
5b5e07d4dc Merge branch 'master' of github.com:laurent22/joplin 2019-10-28 18:19:49 +00:00
Laurent Cozic
4ab1fb3ec5 Not needed 2019-10-23 16:17:40 +01:00
abonte
9dedb832fc Translation: update Italian (it_IT.po) (#2009) 2019-10-20 03:07:40 -04:00
Alex Devero
b8b487991d Translation: update Czech cs_CZ.po (#2007) 2019-10-18 06:00:42 -04:00
Laurent Cozic
f10ba28e0c Update lock.yml 2019-10-18 11:32:23 +02:00
Helmut K. C. Tessarek
22398e69c5 Desktop: Add context menu and menu item to create sub-notebook (#1984)
* add context menu and menu item to create sub-notebook

closes #1978 (create sub-notebook by right-clicking on notebook)

* simplify code, remove async
2019-10-17 22:41:13 +02:00
Caleb John
0eb51e6bb0 Desktop: Stop watching external edits when closing editor (#1981)
* Stop watching external edits

* move onClose to options

* Wrap openExternal in promise

* More specific error with locale

* Removed localization of external edit error
2019-10-17 22:40:27 +02:00
genneko
9436075fdf Translation: Update ja_JP.po Japanese (#2000)
* Translate new strings.
* Improve existing strings.
2019-10-17 00:22:13 -04:00
Woosuk Park
409494afbb Translation: update Korean Langauge (ko.po) (#1989)
* Translation - Korean Langauge

Some change of Korean Language

* Translation - Korean Langauge

Some change of Korean Language
2019-10-16 19:47:47 -04:00
Helmut K. C. Tessarek
a544ebd451 update translations 2019-10-16 19:25:55 -04:00
Xaris Ar
8350a6cc12 Translation: new language Greek (el_GR) (#1997)
* Create el_GR.po (part1)

* Update el_GR.po

* Update el_GR.po (part 2)

* Update el_GR.po

* Finished Greek(el_GR) translation

Finished translating all texts.
Update el_GR.po (beta)
2019-10-16 19:15:55 -04:00
Helmut K. C. Tessarek
b5e7dc5304 Update de_DE.po 2019-10-16 19:07:38 -04:00
Helmut K. C. Tessarek
a11171d73a update translations 2019-10-16 18:14:43 -04:00
Laurent Cozic
4706abbc06 Android release v1.0.309 2019-10-16 23:59:46 +02:00
Laurent Cozic
58b307ba02 Mobile: Resolves #1998: Allow selecting camera ratio and fixed camera view aspect ratio. Also made camera type persistent. 2019-10-16 23:52:22 +02:00
Laurent Cozic
3281ab05b1 Merge branch 'master' of github.com:laurent22/joplin 2019-10-15 00:04:37 +02:00
Laurent Cozic
3a32e79001 Doc: Moved API doc to generation script 2019-10-15 00:04:23 +02:00
Helmut K. C. Tessarek
d91b3624e9 Desktop, Mobile: Add typographer support (#1987)
* add typographer support

* add info to readme/markdown.md
2019-10-15 00:01:58 +02:00
Helmut K. C. Tessarek
d02ced59f8 GitHub: Lock issues that have been closed as stale after 1 day 2019-10-14 17:35:54 -04:00
Laurent Cozic
ba3abf7c4c Update website 2019-10-14 23:28:24 +02:00
Laurent Cozic
cc24398e71 Doc: Add mhchem doc 2019-10-14 23:28:00 +02:00
Laurent Cozic
27d0a8f6e7 GitHub: Lock issues that have been closed as stale after 1 day 2019-10-14 15:44:17 +02:00
Laurent Cozic
4788c46e2c Merge branch 'master' of github.com:laurent22/joplin 2019-10-14 10:35:21 +02:00
Laurent Cozic
0370c7b627 All: Allow apps to work with read-only profile 2019-10-14 10:35:04 +02:00
FoxMaSk
5cbae74086 update API doc related to issue #1956 (#1982)
* update doc related to issue #1956

* Space line
2019-10-14 04:21:51 -04:00
Laurent Cozic
008e30bdb7 Apply linter 2019-10-14 01:47:21 +02:00
Laurent Cozic
a5f17fad58 Android release v1.0.308 2019-10-13 23:19:15 +02:00
Laurent Cozic
22c3646fc6 Electron release v1.0.170 2019-10-13 23:13:19 +02:00
Laurent Cozic
a3e7f0b5ef Tools: Fixed building Android app on Windows 2019-10-13 01:21:56 +02:00
Laurent Cozic
9f5da92ab4 Desktop, Mobile: Added support for chemical equations using mhchem for Katex 2019-10-13 00:22:24 +02:00
Laurent Cozic
fdafe3b947 Desktop: Fixes #1854: Prevent note content from being deleted when using certain external editors (in particular Typora) 2019-10-12 22:51:38 +02:00
Laurent Cozic
6dec711a0a Desktop: Fixes #1854: Prevent external editor from clearing the note in some hard to replicate cases 2019-10-12 21:30:38 +02:00
Laurent Cozic
ec67bc7f1a Mobile: Fixes #1910: Make sure side bar text is white when dark theme is used 2019-10-12 20:55:59 +02:00
Laurent Cozic
47aaf639b3 Merge branch 'master' of github.com:laurent22/joplin 2019-10-12 20:49:42 +02:00
Laurent Cozic
51233c2745 Mobile: Fixes #1975: Images were not being displayed just after having been taken or attached 2019-10-12 20:49:10 +02:00
Laurent Cozic
90bc84c010 Clipper: Fixed: Some tables were imported with a duplicate header 2019-10-12 19:36:06 +02:00
Laurent Cozic
7f1e684dab Updated package to fix tests 2019-10-12 10:47:16 +02:00
Helmut K. C. Tessarek
5f28d0ec24 Desktop: Add option to set page dimensions when printing (#1976)
* add setting: export.pdfPageSize

* create 2 settings: size and orientation

* export.pdfPageOrientation: use string instead of boolean

* add other page formats supported by Electron
2019-10-12 01:21:19 +02:00
Matthew Crumley
348c4ad3a3 Desktop: Resolves #1222: Truncate update changelog when it's too long (#1967)
The changelong text is truncated if it's longer than 1000 characters,
but avoids cutting off a partial line, unless that would lead to cutting
off too much of the text. An ellipsis is added to mark the truncation.

Additionally, when the changelong is truncated, it adds a "Full Release Notes"
button that opens the GitHub release page in a browser window.
2019-10-12 00:44:58 +02:00
J0J0 T
f90cc8d67d Desktop, Cli: enex_to_md: Support italic in span tags (#1966)
* Desktop, Cli: enex_to_md: support italic in span tags

* Desktop, Cli: enex_to_md: readd debug message to resolve CI conflict

* Desktop, Cli: enex_to_md: fix CI errors

add spaces to commented out debug messages

* Desktop, Cli: enex_to_md: remove redundant commented out debug message

* Desktop, Cli: enex_to_md: readd redundant commented out debug message

CI wants it in there - maybe remove in another PR
2019-10-12 00:39:13 +02:00
Alan Martins Silva
d3e9ffcaea Mobile: Added duplicate option when selecting notes. (#1969)
* Adding duplicate button on screen-header.js when selecting notes; Adding 'duplicateMultipleNotes' function on Note.js;

* Using for-loop like the rest of the code does

* changing from 'uniqueTitle' to 'ensureUniqueTitle'
2019-10-12 00:37:16 +02:00
Laurent Cozic
b0a4a10dcc Clipper: Fixes #1876: Handle more styles of named anchors, including spans 2019-10-12 00:18:40 +02:00
Laurent Cozic
8ef5c96cb6 Desktop: Fixes #1970: Display error message when notes cannot be exported 2019-10-11 20:20:12 +02:00
Laurent Cozic
6be36ffe17 Desktop: Fixes #1819: Note view was not reloaded after viewing revisions 2019-10-11 20:10:25 +02:00
Laurent Cozic
7d7975daf4 Cli: Allow setting user timestamps with "set" command 2019-10-11 19:49:47 +02:00
Laurent Cozic
c98644b72f All: Allow a sync client to lock a sync target, so that migration operations can be performed on it 2019-10-11 01:03:23 +02:00
Laurent Cozic
8a097fb79c All: Added concept of sync version and client ID to allow upgrading sync targets 2019-10-10 23:23:11 +02:00
Laurent Cozic
f71e7f4fd3 Update ISSUE_TEMPLATE.md 2019-10-09 22:13:14 +02:00
Laurent Cozic
9c8add97e7 Tests: Add EnexToHtml to the list 2019-10-09 22:10:18 +02:00
Laurent Cozic
b099c811cc Merge branch 'master' of github.com:laurent22/joplin 2019-10-09 21:35:33 +02:00
Laurent Cozic
a8ae0f8078 Apply linter config 2019-10-09 21:35:13 +02:00
Laurent Cozic
d355169b60 Tools: Added rules to linter 2019-10-09 21:33:21 +02:00
Helmut K. C. Tessarek
08295525de Desktop: Add checkmark to menu item, if Dev Tools are on (#1949)
* add checkmark to menu item, if Dev Tools are on

If one closed the dev tools window, one could think that the Dev Tools are closed.
This is not the case. After the next action, the window opens again. This can be
confusing, therefore I added a checkmark to the menu item so that it is very clear.

* fix no-case-declarations

* fix reducer issue
2019-10-09 19:55:35 +02:00
Nathan Leiby
fdcf27fc65 Mobile: confirm encryption password (#1939)
* mobile: confirm encryption password

* pr feedback: translatable strings + style refactor

also added placeholder text

* s/did/do
2019-10-08 18:04:25 -04:00
Caleb John
f2c82b05d9 Desktop: Improved resource hover title (#1965)
* Improved resource hover title

* Add mimetype to resource links

* Escape mime type for resource links
2019-10-08 21:39:38 +02:00
Laurent Cozic
add9dda759 Desktop, Cli: Give correct mime type to more file types 2019-10-08 21:36:33 +02:00
Rafael Cavalcanti
fbba4a1ec4 Fix category on Linux installation script (#1964) 2019-10-08 19:45:08 +02:00
Laurent Cozic
154d303463 Merge branch 'master' of github.com:laurent22/joplin 2019-10-07 23:15:14 +02:00
Laurent Cozic
fdef2db232 Desktop, Cli: Fixes #1960: Apply default style to notes in HTML format 2019-10-07 23:14:49 +02:00
Rafael Cavalcanti
d49fa8e42b Minor fix on install script (#1954) 2019-10-07 22:32:17 +02:00
Irvin Dominin
871d3cb87d Fixed italian locale (#1955)
* Fixed italian locale

* Fixed italian locale

* Revert "Fixed italian locale"

This reverts commit b48695593f.
2019-10-07 16:20:31 -04:00
Laurent Cozic
f1d751b356 Tools: Handle Api commit messages 2019-10-07 10:12:10 +02:00
Laurent Cozic
60c1939d26 Api: Resolves #1956: Allow getting the resources of a note 2019-10-07 09:57:24 +02:00
Devon Zuegel
d2aaac22e5 Desktop: Add loading animation to import/export (#1888)
* Add loading animation to import/export

* Removed unecessary CSS prefixes
2019-10-05 22:46:39 +01:00
Andros Fenollosa
c6842a8591 Update Joplin_install_and_update.sh (#1952)
- Add argument: Mutes messages by console.
- Remove unset.
- Variables in capital letters.
2019-10-05 18:14:45 +01:00
Laurent Cozic
60e9abdd61 GitHub: Remove option to create feature requests 2019-10-04 13:54:07 +01:00
Laurent Cozic
9796630aa2 Update markdown.md 2019-10-04 09:14:18 +01:00
Laurent Cozic
7230cdea33 Doc: Added table example to Markdown cheatsheet 2019-10-04 09:13:24 +01:00
Andros Fenollosa
6460907976 Updating translation es_ES.po (#1947)
* Update language es_ES

* Add Last-Translator

* Translation fix
2019-10-03 17:42:07 -04:00
Helmut K. C. Tessarek
d7a50a1b48 Desktop: Resolves #1662: Set cancel as the default in dangerous operations (#1934)
* set cancel as the  default in dangerous operations, rename buttons (delete, remove) and context menu (for tags)

fixes #1662 (partially, because I can't fix the upstream issue, unless we update Electron)

* add default value for buttonLabel
2019-10-03 22:33:49 +01:00
oskar
4a88343372 Mobile: Added Front Camera toggle when taking a picture (#1913)
* added front camera support

* added front camera button and logic
2019-10-03 22:23:43 +01:00
Helmut K. C. Tessarek
74c2bbc2f0 change tense when passwords do not match 2019-10-02 19:32:32 -04:00
Nathan Leiby
5ed5d16716 Desktop: Resolves #1896: Hide some toolbar buttons when editor hidden (#1940)
addresses issue: https://github.com/laurent22/joplin/issues/1896
2019-10-03 00:07:58 +01:00
Subodh Dahal
43083b0b7a Desktop: Resolves #917: Larger search bar (#1933)
* Increased the width of search bar

* Added some margin to the left ofsearch bar

* Reduced left margin for the search bar
2019-10-02 22:55:29 +01:00
fabianskibr
a4e5054008 Doc: Add AUR repository (#1941) 2019-10-02 22:52:22 +01:00
Laurent Cozic
02eb2f2e45 Desktop, Cli: Resolves #1932: Use profile temp dir when exporting files 2019-10-02 19:22:32 +01:00
Laurent Cozic
5d015bf746 All: Fixes #1906: Fixed translation of "Synchronisation Status" 2019-10-02 19:07:51 +01:00
Laurent Cozic
ce5db5a5c1 Add more logging info to ExternalEditWatcher so that I do not need to ask to enable debug mode 2019-10-02 19:04:50 +01:00
Laurent Cozic
cdcc3902c5 Merge branch 'master' of github.com:laurent22/joplin 2019-10-02 19:03:59 +01:00
Laurent Cozic
309835f2fe Clipper: Fixes #1881: Some pages could not be clipped in Firefox due to an issue with dynamic images 2019-10-02 19:03:36 +01:00
Laurent Cozic
eca0ab0ef6 Desktop: Fixes #1829: Fixed alarms that would trigger immediately when they were set too far in future 2019-10-02 18:21:42 +00:00
Laurent Cozic
4ce35ee1ed Desktop: Fixes #1703: Text input context menu was not working in Windows 2019-10-02 18:05:30 +00:00
Laurent Cozic
8856456afd Doc: Update Markdown page 2019-10-02 08:12:03 +01:00
Helmut K. C. Tessarek
4259d900f4 Mobile: Don't display Dracula theme on mobile (#1935) 2019-10-02 07:49:38 +01:00
Nathan Leiby
438c448ef7 CLI: confirm encryption password (#1937)
Successful flow:
https://gyazo.com/354ca9ea412ffe3756ee77938d544341

Flow with error (non-matching passwords):
https://gyazo.com/9adda69278e3631da33d9fb366815d04
2019-10-02 07:48:58 +01:00
Laurent Cozic
0fb5b35212 All: Fixes #1938: App would crash if trying to index a note that has not been decrypted yet 2019-10-02 07:38:16 +01:00
Laurent Cozic
b69efb4970 Added Markdown Guide to website menu 2019-10-01 22:50:30 +01:00
Laurent Cozic
44ea237538 Merge branch 'master' of github.com:laurent22/joplin 2019-10-01 22:36:11 +01:00
Laurent Cozic
a58316b24c Doc: Fixed Markdown cheat sheet so that it looks better on GitHub 2019-10-01 22:33:19 +01:00
Mats Estensen
df95d01f6e update nb_NO translation to be 100 percent complete (#1930) 2019-10-01 17:32:38 -04:00
Laurent Cozic
d6924893e5 Merge branch 'master' of github.com:laurent22/joplin 2019-10-01 22:28:40 +01:00
Laurent Cozic
0f04ea4f70 Doc: Various changes and added Markdown cheat sheet 2019-10-01 22:27:57 +01:00
Laurent Cozic
4b8026cf83 Update PULL_REQUEST_TEMPLATE 2019-10-01 21:37:55 +01:00
JRaiden
a98a586295 Update es_ES.po (#1929)
I added some translations and change a couple more in order to improve there meaning in Spanish.
I am a native spanish speaker so I could help with some more translate if you want.
2019-10-01 16:32:11 -04:00
Laurent Cozic
29ec7ba03a Apply linter 2019-10-01 19:33:46 +01:00
Helmut K. C. Tessarek
a35cc23d28 Update localization de_DE.po (#1928) 2019-10-01 14:08:33 -04:00
Alexey Pyltsyn
20a8ddd841 Improve Russian translation (#1926) 2019-10-01 14:07:58 -04:00
Davide Cazzin
774fc9ce53 Update Italian translation (#1925) 2019-10-01 14:07:36 -04:00
Dom Goodwin
84ab395fae Desktop: Resolves (#1863): Added Dracula theme (#1924)
* Added dracula theme

* Removed package-lock
2019-10-01 12:23:32 +01:00
Reinhart Previano K
edc4dc5801 Doc: Update React Native build documentation (#1922) 2019-10-01 09:03:31 +01:00
Helmut K. C. Tessarek
6e128a7285 update question template
Somebody deleted the label `question`, so I changed the template to use `invalid`, since a question is technically invalid on the issue tracker.
2019-09-30 19:50:46 -04:00
Helmut K. C. Tessarek
ff977cebaf update issue templates 2019-09-30 19:45:44 -04:00
Caleb John
5bcd5f050a Desktop: Code button now detects multiline (#1915)
* Code button now detects multiline

* Fix text selection for code insertion
2019-09-30 23:24:07 +01:00
Laurent Cozic
fe57f163f3 Merge branch 'master' of github.com:laurent22/joplin 2019-09-30 23:19:31 +01:00
Laurent Cozic
cb24db4e39 Renamed "feature request" to "enhancement" (which is already for feature requests) 2019-09-30 14:57:45 +01:00
Laurent Cozic
e93d96193c eslint 2019-09-29 22:11:36 +00:00
Laurent Cozic
637a4dc1f9 Improve eslint rules and run them from CI 2019-09-29 22:01:10 +00:00
Laurent Cozic
2c522637ef Update website 2019-09-29 15:32:11 +01:00
Laurent Cozic
8fbb1fd246 A bit shorter 2019-09-29 15:32:00 +01:00
Laurent Cozic
75b7e7d999 Update website 2019-09-29 15:30:19 +01:00
Laurent Cozic
7e2e901035 Added note about Hacktoberfest 2019-09-29 15:30:01 +01:00
Laurent Cozic
a73a1f896c Merge branch 'master' of github.com:laurent22/joplin 2019-09-29 14:46:18 +01:00
Laurent Cozic
ae7f0e8ffb Tools: Disable build for macOS on pull requests due to electron-builder bug 2019-09-29 14:46:05 +01:00
abonte
08343e6be9 update translation (#1911) 2019-09-29 14:31:17 +01:00
Laurent Cozic
9cb3496159 Updated Russian translation (Thanks Kirill Keller) 2019-09-29 14:26:51 +01:00
Helmut K. C. Tessarek
37b035d0d0 update issue templates
Some people still ignore the templates. This update makes the important statements more prominent.
2019-09-28 20:48:01 -04:00
genneko
f37ac8b5de Update ja_JP.po Japanese translation. (#1902)
* Translate new strings.
* Check and update 'fuzzy' strings.
2019-09-27 21:31:55 -04:00
Robert
343d04b05d Update nl_NL.po (#1901)
Updated for missing translations in  1.0.168
2019-09-27 21:30:48 -04:00
Laurent Cozic
e92741edd6 CLI v1.0.149 2019-09-27 22:19:13 +01:00
Laurent Cozic
8565cd7d40 Cli: Resolves #1905: Add support to Termux by returning a default when platform name cannot be determined 2019-09-27 22:18:22 +01:00
Laurent Cozic
58e299383d CLI v1.0.148 2019-09-27 19:43:22 +01:00
Laurent Cozic
bcb44aa532 Android release v1.0.307 2019-09-27 19:09:14 +01:00
Laurent Cozic
0c552feb57 Electron release v1.0.169 2019-09-27 19:02:09 +01:00
Laurent Cozic
cd1aa57243 Merge branch 'master' of github.com:laurent22/joplin 2019-09-27 19:01:51 +01:00
Laurent Cozic
c9098b0489 All: Improves deletion fail-safe so it is based on percentage of notes deleted. And display warning on sidebar. 2019-09-27 18:12:28 +00:00
Valentin Deville
117ce52597 Desktop: Add support for Deepin desktop environment in install script (#1884)
* Add support for Deepin desktop environment

* Update Joplin_install_and_update.sh
2019-09-26 21:53:11 +01:00
Laurent Cozic
1836b9a0b0 Merge branch 'master' of github.com:laurent22/joplin 2019-09-26 21:00:28 +01:00
FoxMaSk
563a4b7bd8 Repo: Drop emoji in tag name (#1899) 2019-09-26 20:46:42 +01:00
Laurent Cozic
2a5648d1a7 Tools: Fix build for Android 9 debugging 2019-09-26 19:26:18 +00:00
Laurent Cozic
5b425f9178 Android: Fixes "Row too big to fit into CursorWindow" error by allowing notes up to 50MB in size 2019-09-26 19:11:55 +00:00
Laurent Cozic
820e32ddca Doc: Removed default title in new issue templates
Because otherwise people leave them in, but they are redundant with
the automatically attached tag.
2019-09-26 15:21:00 +01:00
Laurent Cozic
b873e706ca Removed invalid files 2019-09-26 00:54:36 +01:00
Laurent Cozic
f0f6e7c856 Update website 2019-09-26 00:53:57 +01:00
Laurent Cozic
1ff3c7d074 Merge branch 'master' of github.com:laurent22/joplin 2019-09-26 00:53:34 +01:00
Laurent Cozic
393bb8993e Update readme 2019-09-25 22:42:59 +01:00
Helmut K. C. Tessarek
00ddb1eb64 update stale.yml 2019-09-25 17:41:39 -04:00
Laurent Cozic
cd518776a9 Update website 2019-09-25 22:28:48 +01:00
Laurent Cozic
391f7d22a3 CLI v1.0.147 2019-09-25 22:27:58 +01:00
Laurent Cozic
effbf10571 All: Log last requests in case of a sync error 2019-09-25 18:58:15 +00:00
Laurent Cozic
4405e94e0c Android release v1.0.306 2019-09-25 19:52:01 +01:00
Laurent Cozic
69f1b72127 Electron release v1.0.168 2019-09-25 18:54:50 +01:00
Laurent Cozic
383fa2e278 Update translations 2019-09-25 18:54:25 +01:00
Laurent Cozic
573100c203 Merge branch 'master' of github.com:laurent22/joplin 2019-09-25 18:46:52 +01:00
Laurent Cozic
348efdd7b6 All: Added fail-safe to prevent data from being wiped out when the sync target is empty 2019-09-25 18:40:04 +00:00
Laurent Cozic
cb9cc95e6a Doc: Fix email address 2019-09-25 16:29:21 +01:00
Laurent Cozic
1994b334fa Create SECURITY.md 2019-09-25 16:28:34 +01:00
Laurent Cozic
3e5a9cdb97 Tests: Make all tests use asyncTest for better error handling 2019-09-23 23:23:10 +01:00
Laurent Cozic
ae863c95c7 Tests: Make tests and CLI app less dependent on building the translations 2019-09-23 23:01:05 +01:00
Laurent Cozic
e89e5efb62 CI: Fix npm install 2019-09-23 22:45:07 +01:00
Laurent Cozic
9f2ce06829 CI: Build pull requests too 2019-09-23 22:41:22 +01:00
Laurent Cozic
ec89ebc6b0 Make build fail if tests don't pass 2019-09-23 22:37:14 +01:00
Laurent Cozic
f3e9668eb7 Tests: Fail test units when an uncaught exception is thrown inside asyncTest 2019-09-23 22:30:25 +01:00
Laurent Cozic
cc7e2fc456 Merge branch 'master' of github.com:laurent22/joplin 2019-09-23 22:27:16 +01:00
Devon Zuegel
172d925f0f Desktop: Fix import interop service (#1887)
* Revert "Revert "Desktop: Add ENEX to HTML export (#1795)""

This reverts commit 50b66cceca.

* Revert "Revert "Desktop, Cli: Fixed interop service so that it still allow auto-detecting importer based on format (required for Cli and for test units)""

This reverts commit c7c57ab2a5.

* Fix the .md importer

* Add comment re future refactor

* Rm importerClass for .md importer

* Fix EnexToMd module name
2019-09-23 22:18:30 +01:00
Laurent Cozic
8a8ecaade3 Update BUILD.md 2019-09-22 10:54:14 +01:00
Helmut K. C. Tessarek
d21a3f0bca update stale.yml 2019-09-21 14:55:26 -04:00
Helmut K. C. Tessarek
9322212601 update issue templates 2019-09-21 14:50:20 -04:00
Laurent Cozic
691eefec2f Desktop, CLI: Also allow importing TXT files with markdown 2019-09-20 23:00:59 +01:00
Laurent Cozic
50b66cceca Revert "Desktop: Add ENEX to HTML export (#1795)"
This reverts commit 2f14832c34.

Reverting PR #1795 due to broken MD import and other issues
2019-09-20 22:18:09 +01:00
Laurent Cozic
c7c57ab2a5 Revert "Desktop, Cli: Fixed interop service so that it still allow auto-detecting importer based on format (required for Cli and for test units)"
Reverting PR #1795 due to broken MD import and other issues

This reverts commit 558b6443bc.
2019-09-20 22:13:34 +01:00
Laurent Cozic
558b6443bc Desktop, Cli: Fixed interop service so that it still allow auto-detecting importer based on format (required for Cli and for test units) 2019-09-19 23:26:33 +01:00
Laurent Cozic
335b43ead4 Chore: Fixed a few formatting issues 2019-09-19 23:02:29 +01:00
Laurent Cozic
e648392330 Chore: Apply eslint rules 2019-09-19 22:51:18 +01:00
Laurent Cozic
ab29d7e872 Chore: Add line break style, and use of template to eslint rules 2019-09-19 22:49:17 +01:00
Woosuk Park
d7fae6b5b8 Update ko.po - korean language support (#1875) 2019-09-17 20:43:38 -04:00
Devon Zuegel
4ba4910a9c Mobile: Custom mobile editor font (#1797)
* Make editor font "Menlo"

* Add .vscode/* to .gitignore

* Add "editor font" config UI

* Render "editor font" chosen in config

* Add shim.mobilePlatform()

* Use style.editor.fontFamily rather than editorFont

* Add default font option

* Fixed for Android
2019-09-17 21:32:00 +01:00
Laurent Cozic
fe9a037cf9 Chore: Fixed package.json files and updated BUILD instructions 2019-09-17 21:29:37 +01:00
Devon Zuegel
2f14832c34 Desktop: Add ENEX to HTML export (#1795)
* Add `escape` to go back from Dropbox Login screen

* Add .vscode/ to .gitignore

* Remove call to enexXmlToMd

* The 2 enex importers have distinct functionality!

* Add tmp #deleteAllNotebooks

* checkbox state still not persisting

* images now fixed, but checkboxes still broken

* Figured out that #ipcProxySendToHost is important for handling checkbox

* cleanup closing br and en-todo tags + add notes

* Handle en-media, add NOTEs & TODOs, & format html

* Clean up some of the logging

* cleanHtml is a nice beautifier, but callback hell ensues...

* Rm #htmlFormat

* Recreating the xml actually seems to work

* Add test (not functional rn)

* Add test for checkboxes

* Add test for image en-media

* Separate tests into 2 function calls

* Clean up test

* Add `en-media-audio` test

* Add bad resource test

* Misc cleanup

* Rm SlateEditor files

* Misc cleanup

* Remove #deleteAllNotebooks button

* Add names to tests

* Extract resourceUtils

* Rm DropboxLoginScreen esc behavior, part of another PR

* Misc cleanup

* Improve audioElement, add attachment import support

* Misc cleanup

* Add svg test for enex_to_html

* Clean up test

* Set markup_language to MARKUP_LANGUAGE_HTML to tell renderer that the content is only HTML

* Rename to newModuleByFormat_ for clarity

* Add comment to clarify newModuleFromPath_
2019-09-17 21:19:32 +01:00
Laurent Cozic
52ace55db0 Mobile: Remove empty sections from config screen 2019-09-16 22:59:45 +01:00
Laurent Cozic
224a4d786b Desktop: Fixed broken menu bar 2019-09-16 22:54:40 +01:00
腹肌抽筋了
3ea97ad9ff Update zh_CN.po Chinese translation (#1871) 2019-09-15 00:02:53 -04:00
Laurent Cozic
e7a56bb2b1 ios-v10.0.37 2019-09-13 22:08:13 +01:00
Laurent Cozic
e4aed469d7 Chore: Add reslect to package 2019-09-13 22:05:02 +01:00
Laurent Cozic
15a42a3729 Chore: Apply eslint no-unused-vars eslint config and add TypeScript config 2019-09-12 22:16:42 +00:00
Laurent Cozic
0b9e007b46 Merge branch 'master' of github.com:laurent22/joplin 2019-09-12 22:48:49 +01:00
Laurent Cozic
88561a6c3c Desktop, CLI: Fixed import of notes that contain links with hashes 2019-09-12 22:48:10 +01:00
genneko
e6b77c3381 Update ja_JP.po Japanese translation (#1868)
* Update Japanese translation (Fix typos).

* Update Japanese translation (Improve the wording).

* Update Japanese translation (Add new items).
2019-09-12 17:38:48 -04:00
abonte
f7e1589476 Update it_IT.po (#1866) 2019-09-12 17:37:34 -04:00
Laurent Cozic
0379523eaf Desktop, Mobile: Fixes #1870: Support non-alphabetical characters in note link anchors 2019-09-12 21:57:23 +01:00
Laurent Cozic
5db7502fe4 Merge branch 'tidy_config' 2019-09-11 23:00:03 +01:00
Laurent Cozic
1578188fde Update website 2019-09-11 11:18:44 +01:00
Laurent Cozic
e8e1a0fe4d Desktop: Cleaned up and improved config screen design, move all screens under same one, and added section buttons 2019-09-10 23:53:01 +00:00
Laurent Cozic
8059009ff3 Android release v1.0.305 2019-09-10 09:31:48 +01:00
Laurent Cozic
32865f065c Electron release v1.0.167 2019-09-10 09:26:26 +01:00
Laurent Cozic
e03ef78049 All: Fixed link issue following last update 2019-09-10 09:25:58 +01:00
Laurent Cozic
45a820bb35 Update website 2019-09-09 19:03:22 +01:00
Laurent Cozic
3c26159b79 Doc: Add link to 32-bit Android APK to readme and website 2019-09-09 18:58:35 +01:00
Laurent Cozic
cf67e0d4af Tools: Allow specifying "to" commit option in git-changelog 2019-09-09 18:50:04 +01:00
Laurent Cozic
1b2767167d Cli: Upgrade joplin-turndown-plugin-gfm to fix import of certain Enex tables 2019-09-09 18:35:22 +01:00
Laurent Cozic
f07bb5c275 Android release v1.0.304 2019-09-09 18:26:55 +01:00
Laurent Cozic
0e2cc418e2 Electron release v1.0.166 2019-09-09 18:22:42 +01:00
Laurent Cozic
0340456d55 Update translations 2019-09-09 18:22:20 +01:00
Laurent Cozic
7aea2cec69 Desktop: Resolves #1490: Add support for anchor hashes in note links 2019-09-09 18:16:00 +01:00
Laurent Cozic
fa83107840 Doc: Update CLI installation info 2019-09-08 20:21:14 +01:00
Laurent Cozic
bb0bf46f81 CLI v1.0.146 2019-09-08 20:12:49 +01:00
Laurent Cozic
694c3fed2d Cli: Fixed regression that was making installation fail 2019-09-08 20:12:25 +01:00
Laurent Cozic
772e39b710 Tools: Improved git-changelog so that it is less error prone 2019-09-08 17:54:41 +01:00
Laurent Cozic
05e0a2c29d CLI v1.0.145 2019-09-08 17:24:00 +01:00
Laurent Cozic
78e0efb95f Trying CLI release 2019-09-08 17:19:22 +01:00
Laurent Cozic
a5f749cfd2 Tools: Added moment package 2019-09-08 17:18:44 +01:00
Laurent Cozic
3d6c932e1b Cli: Added headless server command (Beta) (#1860)
* Trying to implement headless server

* Cli: Cleaned up and completed server command so that it is usable. Added warnings as it is advanced usage only at this point.

* Restored welcome assets
2019-09-08 17:16:45 +01:00
archont00
4488a1b95f Doc: Update explanation of enabling E2EE (#1859)
As per https://discourse.joplinapp.org/t/totally-confused-re-e2ee/3295, I tried to improve the explanation of the process to avoid multiple encryption keys.
2019-09-08 16:35:10 +01:00
archont00
e2808a90c6 Doc: Update re. impossibility to delete unused Master Keys (#1858)
As per discussion at https://discourse.joplinapp.org/t/totally-confused-re-e2ee/3295/2, I propose to add info about Master Keys persistence.
2019-09-08 16:34:37 +01:00
Laurent Cozic
755a972e02 Update website 2019-09-08 11:09:02 +01:00
Laurent Cozic
8b1de22049 Merge branch 'master' of github.com:laurent22/joplin 2019-09-08 11:07:54 +01:00
Laurent Cozic
a9735123b7 Doc: Added warning to generated HTML files 2019-09-08 11:06:53 +01:00
Laurent Cozic
5ccafa2838 Doc: Added warning to generated HTML files 2019-09-08 10:46:35 +01:00
archont00
e2926a4f82 Doc: Update explanation of enabling E2EE (#1856)
As per https://discourse.joplinapp.org/t/totally-confused-re-e2ee/3295, I tried to improve the explanation of the process to avoid multiple encryption keys.
2019-09-08 10:35:15 +01:00
Laurent Cozic
09df315639 Desktop: Fixes #1833: Do not scroll text when search is open and user type in note 2019-09-07 11:57:31 +01:00
Laurent Cozic
5a9b3b6c7c Desktop, Mobile: Resolves #1832: Only support checkboxes that start with a dash 2019-09-07 11:18:07 +01:00
Laurent Cozic
6da6f35ddd Merge branch 'master' of github.com:laurent22/joplin 2019-09-07 10:47:51 +01:00
Laurent Cozic
dcb5590842 Clipper: Fixes #1851: Fixed error when trying to import certain pages using "Clip simplified page" feature 2019-09-07 10:47:31 +01:00
Laurent Cozic
5135c8a782 Clipper: Fixes #1783: Fixed importing tables that contain pipes 2019-09-07 10:32:52 +01:00
Laurent Cozic
1b2f4fb036 Update bug_report.md 2019-09-07 10:09:05 +01:00
Laurent Cozic
76a4a445f0 Doc: Added info about SKIP_PREFLIGHT_CHECK 2019-09-07 09:56:06 +01:00
Helmut K. C. Tessarek
20abb125a5 infrastructure: skip preflight check for building clipper 2019-09-06 13:53:35 -04:00
Laurent Cozic
be9e50b4a1 Update FUNDING.yml 2019-09-06 18:48:05 +01:00
Helmut K. C. Tessarek
02bfcf577d Clipper release v1.0.18 2019-09-06 13:37:55 -04:00
Laurent Cozic
038efa10f2 Update website 2019-09-06 18:34:47 +01:00
Laurent Cozic
dfa692569b Update translations 2019-09-06 18:33:30 +01:00
Laurent Cozic
9abc6a2e44 CLI: Fixes #1779: Make sure setting side-effects are applied even when running in command line mode 2019-09-06 18:29:40 +01:00
Laurent Cozic
11f23f4e00 Android release v1.0.303 2019-09-06 17:51:38 +01:00
Laurent Cozic
6a7d40d171 Merge branch 'master' of github.com:laurent22/joplin 2019-09-06 17:50:39 +01:00
Laurent Cozic
bf5601429e Mobile: Fixes #1767: Fixed broken search when certain notes are too large 2019-09-06 17:39:36 +01:00
abonte
73ae8aaf2f Update it_IT.po (#1853) 2019-09-05 22:45:36 -04:00
axq
7eb7bd98f3 Doc: Minor English improvements in README.md (#1852) 2019-09-05 17:11:45 +01:00
Laurent Cozic
10e22654ea Desktop: Fixes #1815: Fixed cropped content issue when printing or exporting to PDF 2019-09-04 20:11:35 +01:00
Joan Montané
ccfc80ad04 Update ca.po (#1836) 2019-08-29 17:39:35 +01:00
stellarpower
5e95278084 Fix Cinnamon Detection (#1828)
$desktop was converted to lowercase, but matched against 'X-Cinnamon'
2019-08-29 17:39:10 +01:00
Helmut K. C. Tessarek
d69ba6bc75 All: fix typo on encryption options screen (#1823)
fixes #1798
2019-08-29 17:38:54 +01:00
Caleb John
d28fbe2d3b Desktop: Apply current locale to date and time (#1822) 2019-08-29 17:38:24 +01:00
Caleb John
415e7b84da Desktop: Change localeCompare functiion for tags (#1811)
* change localeCompare functin for tags

* Fix spacing
2019-08-29 17:36:53 +01:00
Caleb John
ac4986b620 Desktop: Fixes #1803: Use correct date format for templates (#1810) 2019-08-29 17:35:43 +01:00
Caleb John
9a4f4cbb65 Desktop: Change template prompt to sans and sort templates (#1806)
* Change template prompt to sans and sort templates

* Sort templates by filename to ensure order
2019-08-29 17:34:54 +01:00
Helmut K. C. Tessarek
8e32957111 Infrastructure: build-translation.js - add support for macOS (#1804)
* remove unnecessary comment

It's totally fine to add the double quotes after -i.
Using gsed would mean that people had to install GNU sed. For what, if the same is possible with the system's sed with a slight modification.
Checking for gsed and using it is more trouble than it's worth.

* build-translation.js: add support for macOS

* implement requested changes
2019-08-29 17:34:05 +01:00
Helmut K. C. Tessarek
91aa3703d4 CLI: Fixes fatal error with cli 1.0.141 on start (#1791)
- updated terminal-kit to 1.30.0
- do not call method, if object does not exist

fixes #1778
2019-08-29 17:05:20 +01:00
FoxMaSk
a889762056 Update README.md
Double line fixed
2019-08-21 10:14:15 +02:00
Robert
6478d6c9c9 Update nl_NL.po (#1821) 2019-08-19 17:59:43 -04:00
FoxMaSk
7a681d0a4a README: add Discord Community Server (#1800)
* Discord Community Server

* Discord Server Link fixed

* improvment
2019-08-19 13:34:43 -04:00
Rafael Teixeira
83b6eba8bd Updated Last Translator pt_BR (#1813) 2019-08-17 02:36:25 -04:00
Helmut K. C. Tessarek
2766ded5f6 Update website 2019-08-16 19:55:27 -04:00
Rafael Teixeira
ca0d966ed9 Translation: Translation Update pt_BR (#1809)
* Updated translation pt-BR

* New updates translation pt_BR
2019-08-16 03:58:07 -04:00
Woosuk Park
386c583b0e Translation : Korean Translation #2 (#1802)
* Korean Language Support

Korean Language 100% Translated, but something is roughted. soon fix it ;)

* some improved

Some Improved

* Improve v2

some polished

* Ok, now Completed

For Now, Completed Polish(Change Respect of Users, and several fixing & polishing) + 100% Translated. Ready to Shipping

* Korean Language Update #2

1. 조플린 -> Joplin (Sorry i forgot)
2. Fuzzy correction.

Korean Language Update #2

1. 조플린 -> Joplin (Sorry i forgot)
2. Fuzzy correction.
2019-08-15 13:15:32 -04:00
Laurent Cozic
b3d34ad7e9 Android release v1.0.299 2019-08-14 23:47:38 +02:00
Laurent Cozic
ba5c636dda Android: Fixed AndroidX transition issue 2019-08-14 23:44:57 +02:00
Laurent Cozic
ea16f6e0b1 Revert "Trying to fix Android buikld"
This reverts commit 0dd0dc5489.
2019-08-14 23:23:27 +02:00
Laurent Cozic
0dd0dc5489 Trying to fix Android buikld 2019-08-14 23:22:52 +02:00
Laurent Cozic
f3ab21ff43 Electron release v1.0.165 2019-08-14 23:17:25 +02:00
Laurent Cozic
5ac6b46efd Desktop: Fixed theme options for Solarized theme 2019-08-14 23:17:02 +02:00
Laurent Cozic
6548f30a4b Electron release v1.0.164 2019-08-14 22:49:45 +02:00
Laurent Cozic
849d7983f6 Desktop: Added support for Fountain screenwriting language 2019-08-14 12:40:06 +02:00
Helmut K. C. Tessarek
e32e4423db change feature request template 2019-08-14 02:08:35 -04:00
Laurent Cozic
7f5bf131a8 Add back files that might have been modified by linter 2019-07-30 11:40:33 +02:00
Laurent Cozic
87a639df2b Mobile: Disabled solarized themes on mobile 2019-07-30 11:37:52 +02:00
Laurent Cozic
bdd8eab87e Mobile: Make it clearer when there are no notebooks and added a button create one 2019-07-30 11:36:56 +02:00
Laurent Cozic
b9e5c8a387 Electron release v1.0.163 2019-07-30 09:52:26 +02:00
Laurent Cozic
d646a2dd01 Fix Linux and macOS build to go around this bug: https://github.com/electron-userland/electron-builder/issues/3179 2019-07-30 09:52:16 +02:00
Laurent Cozic
71a3a0176e Android release v1.0.294 2019-07-30 09:42:09 +02:00
Laurent Cozic
a363d119cf Electron release v1.0.162 2019-07-30 09:37:23 +02:00
Laurent Cozic
ff08bdbc0b Merge branch 'master' of github.com:laurent22/joplin 2019-07-30 09:35:49 +02:00
Laurent Cozic
71efff6827 Linter update (#1777)
* Update eslint config

* Applied linter to lib

* Applied eslint config to CliClient/app

* Removed prettier due to https://github.com/prettier/prettier/pull/4765

* First pass on test units

* Applied linter config to test units

* Applied eslint config to clipper

* Applied to plugin dir

* Applied to root of ElectronClient

* Applied on RN root

* Applied on CLI root

* Applied on Clipper root

* Applied config to tools

* test hook

* test hook

* test hook

* Added pre-commit hook

* Applied rule no-trailing-spaces

* Make sure root packages are installed when installing sub-dir

* Added doc
2019-07-30 09:35:42 +02:00
Laurent Cozic
7595fe4a8c Merge branch 'master' of github.com:laurent22/joplin 2019-07-30 09:32:34 +02:00
Laurent Cozic
7697e75466 Update eslint config 2019-07-29 21:23:14 +02:00
Helmut K. C. Tessarek
b8fbaa2029 Update en_US.po 2019-07-29 11:34:52 -04:00
Helmut K. C. Tessarek
38bc750ecf Update de_DE.po 2019-07-29 11:34:02 -04:00
Laurent Cozic
6cfacb1a48 Second pass at linting lib dir 2019-07-29 15:58:33 +02:00
Laurent Cozic
0b9078d034 config 2019-07-29 15:58:17 +02:00
Laurent Cozic
86dc72b204 First pass at linting lib dir 2019-07-29 15:43:53 +02:00
Laurent Cozic
64b7bc3d62 More config 2019-07-29 15:43:39 +02:00
Laurent Cozic
086f9e1123 Started applying config to Electron app 2019-07-29 14:13:23 +02:00
Laurent Cozic
4fe70fe8ee Ignore some files 2019-07-29 14:13:09 +02:00
Laurent Cozic
95a1f40404 Tweaked linter config 2019-07-29 14:10:07 +02:00
Laurent Cozic
88f04509ee Also added prettier config 2019-07-29 13:48:43 +02:00
Laurent Cozic
7eebd544d6 Fixed eslint 2019-07-29 12:55:50 +02:00
Laurent Cozic
e369a8decf Added eslint config 2019-07-29 12:55:39 +02:00
Helmut K. C. Tessarek
ad8054ba4b Desktop: Better handling of adding the title to print and export to PDF (#1744)
fixes #1743
2019-07-29 12:33:40 +02:00
J0J0 T
b47cb4e29a Desktop, Cli: Improved bold formatting support in Enex import (#1708)
* Dekstop,CLI: enex_to_md: add html/md test file pairs

* one pair for basic text formatting tags: strong, b, i, em
* and one using span tags with inline styles for bold formatting

Note: The html files include the Evernote-typical "linebreak tags inside of separate <div> tags"
to represent empty lines!

* Desktop,Cli: enex_to_md: support bold in span tags using inline styles

* function isSpanWithStyle() checks if further processing of a span tag
  makes sense
* function isSpanStyleBold() checks if bold formatting via styles is
  used - a similar function could be written for each span-inline-style-format
  that should be supported

* Desktop,Cli: enex_to_md: fix saving span attrs in state object

pushing attributes of span tag to state object now
happens outside of isSpanWithStyle()
2019-07-29 12:25:25 +02:00
Laurent Cozic
8c42ddf6c3 Merge branch 'master' of github.com:laurent22/joplin 2019-07-29 12:17:33 +02:00
tfinnberg
f7fcabbf41 Desktop: Create fileURLs via drag and drop (#1653)
* enable drag and drop fileURLs

* fix windows fileURL syntax

* introduce encodeURI function

* fixed encoding issue

* use path-utils.js to deal with fileURL path conversion

* add changes as requested

* Minor rewording 'On the' -> 'In the', additional info about attaching files

* change call of toFileProtocolPath

* enable test script to check syntax for all OS-platforms
2019-07-29 12:16:47 +02:00
Shane Kilkelly
38a51070fc Desktop: add depthColor for solarized light and dark themes (#1765) 2019-07-29 12:08:49 +02:00
Laurent Cozic
44fa099a77 Desktop: No longer crash if certain theme properties are not set 2019-07-29 12:05:58 +02:00
sumomo-99
af6f3999df Update ja_JP.po (#1776) 2019-07-29 11:55:02 +02:00
Laurent Cozic
6fbeb35951 Update translations 2019-07-29 11:52:19 +02:00
Laurent Cozic
b2eadffde0 Using British English by default for consistency 2019-07-29 11:51:09 +02:00
Laurent Cozic
200ba2775f All: Resolves #1459: Make translation files smaller by not including untranslated strings. Also add percentage translated to config screen. 2019-07-29 11:47:50 +02:00
Laurent Cozic
39ba021a79 Merge branch 'master' of github.com:laurent22/joplin 2019-07-29 10:12:45 +02:00
Laurent Cozic
2c6b291b9b Desktop: Only repeat failed requests up to 3 times during sync 2019-07-29 10:12:23 +02:00
Devon Zuegel
770846be2e Doc: Add docs to clarify how to test (#1775) 2019-07-29 09:42:10 +02:00
Laurent Cozic
af4aa01b75 Mobile: Upgraded packages to fix security issues 2019-07-28 23:03:54 +02:00
Laurent Cozic
1bf2bec805 CLI v1.0.141 2019-07-28 22:54:45 +02:00
Laurent Cozic
3a41ac9be0 CLI: Upgraded packages to fix security issues 2019-07-28 22:54:29 +02:00
Laurent Cozic
f2c9cdd7f1 Desktop: Upgraded packages to fix security issue 2019-07-28 22:48:30 +02:00
Laurent Cozic
058f418cc7 Tools: Do not display full release info when releasing Android app 2019-07-28 22:43:33 +02:00
Laurent Cozic
5fa84b0dfb Android release v1.0.293 2019-07-28 18:36:36 +02:00
Laurent Cozic
ec8ec3e38d Android release v1.0.292 2019-07-28 18:34:44 +02:00
Laurent Cozic
0e6190b42b Tools: Allow creating multiple Android releases 2019-07-28 18:33:48 +02:00
Laurent Cozic
fcfee36c8c Android release v1.0.291 2019-07-28 18:32:33 +02:00
Laurent Cozic
1d3d3b99bb Tools: Allow creating multiple Android releases 2019-07-28 18:31:31 +02:00
Laurent Cozic
2f80bf9647 Android release v1.0.290 2019-07-28 18:29:07 +02:00
660 changed files with 50730 additions and 20661 deletions

48
.eslintignore Normal file
View File

@@ -0,0 +1,48 @@
*.min.js
.git/
.github/
_mydocs/
_releases/
Assets/
CliClient/build
CliClient/locales
CliClient/node_modules
CliClient/tests-build
CliClient/tests/enex_to_md
CliClient/tests/html_to_md
CliClient/tests/logs
CliClient/tests/support
CliClient/tests/sync
CliClient/tests/tmp
Clipper/joplin-webclipper/content_scripts/JSDOMParser.js
Clipper/joplin-webclipper/content_scripts/Readability-readerable.js
Clipper/joplin-webclipper/content_scripts/Readability.js
Clipper/joplin-webclipper/dist
Clipper/joplin-webclipper/icons
Clipper/joplin-webclipper/popup/build
Clipper/joplin-webclipper/popup/node_modules
docs/
ElectronClient/app/dist
ElectronClient/app/lib
ElectronClient/app/lib/vendor/sjcl-rn.js
ElectronClient/app/lib/vendor/sjcl.js
ElectronClient/app/locales
ElectronClient/app/node_modules
highlight.pack.js
node_modules/
ReactNativeClient/android
ReactNativeClient/ios
ReactNativeClient/lib/vendor/
ReactNativeClient/lib/welcomeAssets.js
ReactNativeClient/locales
ReactNativeClient/node_modules
readme/
Tools/node_modules
Tools/PortableAppsLauncher
Server/.git/
Server/.github/
Server/docs/
Server/dist/
Server/bin/
Server/node_modules/
ElectronClient/app/packageInfo.js

85
.eslintrc.js Normal file
View File

@@ -0,0 +1,85 @@
module.exports = {
'env': {
'browser': true,
'es6': true,
'node': true,
},
"parser": "@typescript-eslint/parser",
'extends': ['eslint:recommended'],
'globals': {
'Atomics': 'readonly',
'SharedArrayBuffer': 'readonly',
// Jasmine variables
'expect': 'readonly',
'describe': 'readonly',
'it': 'readonly',
'beforeEach': 'readonly',
'jasmine': 'readonly',
// React Native variables
'__DEV__': 'readonly',
// Clipper variables
'browserSupportsPromises_': true,
'chrome': 'readonly',
'browser': 'readonly',
},
'parserOptions': {
'ecmaVersion': 2018,
"ecmaFeatures": {
"jsx": true,
},
"sourceType": "module",
},
'rules': {
// -------------------------------
// Code correctness
// -------------------------------
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"no-unused-vars": "error",
"no-constant-condition": 0,
"no-prototype-builtins": 0,
// This error is always a false positive so far since it detects
// possible race conditions in contexts where we know it cannot happen.
"require-atomic-updates": 0,
// "no-lonely-if": "error",
// -------------------------------
// Formatting
// -------------------------------
"space-in-parens": ["error", "never"],
"semi": ["error", "always"],
"eol-last": ["error", "always"],
"quotes": ["error", "single"],
"indent": ["error", "tab"],
"comma-dangle": ["error", "always-multiline"],
"no-trailing-spaces": "error",
"linebreak-style": ["error", "unix"],
"prefer-template": ["error"],
"template-curly-spacing": ["error", "never"],
"key-spacing": ["error", {
"beforeColon": false,
"afterColon": true,
"mode": "strict"
}],
"block-spacing": ["error"],
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"no-spaced-func": ["error"],
"func-call-spacing": ["error"],
"space-before-function-paren": ["error", {
"anonymous": "never",
"named": "never",
"asyncArrow": "always"
}],
"multiline-comment-style": ["error", "separate-lines"],
"space-before-blocks": "error",
"spaced-comment": ["error", "always"],
"keyword-spacing": ["error", { "before": true, "after": true }]
},
"plugins": [
"react",
"@typescript-eslint",
],
};

1
.github/FUNDING.yml vendored
View File

@@ -1,4 +1,5 @@
# These are supported funding model platforms
patreon: joplin
github: laurent22
custom: https://joplinapp.org/donate/

View File

@@ -1,4 +1,9 @@
👉 Please follow one of these issue templates:
- https://github.com/laurent22/joplin/issues/new/choose
⚠️
The GitHub issue tracker is for **bugs** and **security issues** ONLY. For feature requests and support, please use the forum:
https://discourse.joplinapp.org/
⚠️
Note: to keep the backlog clean and actionable, issues may be immediately closed if they do not follow one of the above issue templates.

View File

@@ -12,6 +12,11 @@ labels: 'bug'
Please test using the latest Joplin release to make sure your issue has not already been fixed.
-->
<!--
IMPORTANT: If you are reporting a clipper bug, please include an example URL that shows the issue.
Without the URL the issue is likely to be closed.
-->
## Environment
Joplin version:

View File

@@ -1,33 +0,0 @@
---
name: Feature request
about: Suggest a feature for Joplin.
title: '[Feature request] '
labels: 'feature request'
---
<!--
Please search open issues first - many features have already been requested!
-->
## Has it been discussed in the forum? Link to topic.
<!--
Feature requests should be discussed in the forum first. https://discourse.joplinapp.org
Please provide a link to the topic.
-->
## Is your feature request related to a problem? Please describe.
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
## Describe the solution you'd like
<!-- A clear and concise description of what you want to happen. -->
## Describe alternatives you've considered
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
## Additional context
<!-- Add any other context or screenshots about the feature request here. -->

View File

@@ -1,12 +1,12 @@
---
name: "🤔 Questions and Help"
about: The issue tracker is not for questions. Please ask questions on https://discourse.joplinapp.org/.
title: 'Question: '
labels: 'question'
title: ''
labels: 'invalid'
---
🚨 The issue tracker is not for questions. 🚨
⚠🚨⛔ 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.

View File

@@ -6,6 +6,8 @@ Please prefix the title with the platform you are targetting:
- "Mobile" for the mobile app (or "Android" / "iOS" if the pull request only applies to one of the mobile platforms)
- "CLI" for the CLI app
If it's not related to any platform (such as a translation, change to the documentation, etc.), simply don't add a platform.
For example: "Desktop: Added new setting to change font", or "Mobile: Fixed config screen error"
PLEASE READ THE GUIDE FIRST: https://github.com/laurent22/joplin/blob/master/CONTRIBUTING.md

25
.github/lock.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
# Configuration for Lock Threads - https://github.com/dessant/lock-threads
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 7
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
skipCreatedBefore: false
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
exemptLabels: []
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: false
# Comment to post before locking. Set to `false` to disable
lockComment: false
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: false
# Limit to only `issues` or `pulls`
only: issues
# Optionally, specify configuration settings just for `issues` or `pulls`
# issues:
# exemptLabels:
# - help-wanted
# lockLabel: outdated
# pulls:
# daysUntilLock: 30
# Repository to extend settings from
# _extends: repo

2
.github/stale.yml vendored
View File

@@ -17,7 +17,7 @@ staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs.
You may also label this issue as "backlog" and I will leave it open.
You may comment on the issue and I will leave it open.
Thank you for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: >

3
.gitignore vendored
View File

@@ -42,4 +42,5 @@ ReactNativeClient/lib/csstojs/
ReactNativeClient/lib/rnInjectedJs/
ElectronClient/app/gui/note-viewer/fonts/
ElectronClient/app/gui/note-viewer/lib.js
Tools/commit_hook.txt
Tools/commit_hook.txt
.vscode/*

View File

@@ -1,5 +1,5 @@
# Only build tags (Doesn't work - doesn't build anything)
if: tag IS present
if: tag IS present OR type = pull_request
rvm: 2.3.3
@@ -54,8 +54,47 @@ before_install:
script:
- |
# Install tools
npm install
cd Tools
npm install
cd ../ElectronClient/app
cd ..
# Run test units.
# Only do it for pull requests because Travis randomly fails to run them
# and that would break the desktop release.
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
cd CliClient
npm install
./run_test.sh
testResult=$?
if [ $testResult -ne 0 ]; then
exit $testResult
fi
cd ..
fi
# Run linter for pull requests only - this is so that
# bypassing eslint is allowed for urgent fixes.
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
npm run linter-ci ./
testResult=$?
if [ $testResult -ne 0 ]; then
exit $testResult
fi
fi
# Find out if we should run the build or not. Electron-builder gets stuck when
# builing PRs so we disable it in this case. The Linux build should provide
# enough info if the app builds or not.
# https://github.com/electron-userland/electron-builder/issues/4263
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
exit 0
fi
fi
# Prepare the Electron app and build it
cd ElectronClient/app
rsync -aP --delete ../../ReactNativeClient/lib/ lib/
npm install && yarn dist
npm install && USE_HARD_LINKS=false yarn dist

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 36 KiB

19
Assets/JoplinIcon.svg Normal file
View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 682.66669 682.66669" height="682.66669" width="682.66669" xml:space="preserve" id="svg2" version="1.1">
<defs id="defs6">
<linearGradient id="linearGradient26" spreadMethod="pad" gradientTransform="matrix(-4387.91,4387.91,4387.91,4387.91,4753.95,366.05)" gradientUnits="userSpaceOnUse" y2="0" x2="1" y1="0" x1="0">
<stop id="stop22" offset="0" style="stop-opacity:1;stop-color:#004caf"/>
<stop id="stop24" offset="1" style="stop-opacity:1;stop-color:#1f95f8"/>
</linearGradient>
</defs>
<g transform="matrix(1.3333333,0,0,-1.3333333,0,682.66667)" id="g10">
<g transform="scale(0.1)" id="g12">
<g id="g14">
<g clip-path="url(#clipPath20)" id="g16">
<path id="path28" style="fill:url(#linearGradient26);fill-opacity:1;fill-rule:nonzero;stroke:none" d="M 3873.89,0 H 1246.11 C 560.754,0 0,560.75 0,1246.11 V 3873.88 C 0,4559.25 560.754,5120 1246.11,5120 H 3873.89 C 4559.25,5120 5120,4559.25 5120,3873.88 V 1246.11 C 5120,560.75 4559.25,0 3873.89,0"/>
</g>
</g>
<path id="path30" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" d="M 3961.59,4435.23 H 2570.18 c -13.15,0 -23.78,-10.64 -23.78,-23.77 v -441.84 c 0,-14.87 12.04,-26.92 26.92,-26.92 h 190.77 c 77.16,0 139.73,-59.35 146.43,-134.77 V 3505 3336.23 1728.75 1717.36 h -0.05 c 0.48,-16.84 -0.19,-33.4 -1.83,-49.71 -0.18,-2.38 -0.5,-4.73 -0.79,-7.09 -1.1,-9.53 -2.32,-19.01 -4.17,-28.29 -1.01,-5.29 -2.44,-10.44 -3.71,-15.65 -1.71,-6.93 -3.09,-13.97 -5.22,-20.75 -12.58,-40.27 -32.47,-77.62 -59.98,-110.5 -1.01,-1.17 -2.26,-2.25 -3.26,-3.41 -8.39,-9.72 -17.2,-19.19 -26.95,-28.06 -9.84,-8.95 -20.26,-17.27 -31.21,-25 -77.84,-55.14 -182.61,-79.4 -299.67,-68.2 -149.26,14.03 -297.34,81.72 -417.03,190.62 -119.67,108.89 -194.08,243.62 -209.48,379.41 -13.85,121.48 22.55,228.38 102.42,301.05 0.21,0.16 0.4,0.31 0.56,0.48 3.09,2.77 6.49,5.2 9.67,7.87 57.16,47.89 131.67,76.91 216.7,84.91 0.96,0.09 1.88,0.24 2.79,0.32 8.95,0.79 18.07,1.15 27.27,1.49 4.81,0.16 9.56,0.5 14.44,0.54 1.62,0.02 3.16,0.19 4.78,0.19 2.9,0 5.91,-0.38 8.81,-0.42 13.4,-0.21 26.9,-0.76 40.67,-1.94 1.74,-0.14 3.4,-0.08 5.19,-0.24 1.27,-0.13 2.53,-0.41 3.8,-0.54 78,-7.82 155.23,-31.11 228.52,-66.4 1.53,-0.07 3.3,-0.54 5.51,-1.76 22.34,-12.34 26.62,0.9 27.28,9.65 v 382.24 282.82 c 0,19.05 -13.25,35.9 -31.83,39.99 -394.76,86.88 -782.08,-3.55 -1055.38,-252.34 -238.75,-217.18 -354.24,-530.58 -316.82,-859.79 33.39,-293.23 183.91,-574.94 423.88,-793.33 233.89,-212.79 531.69,-345.86 838.88,-374.801 42.33,-3.918 84.86,-5.938 126.36,-5.938 293.38,0 565.61,100.598 766.54,283.379 190.34,173.3 304.35,411.27 321.08,670.16 l 1.55,1697.91 h 0.17 v 453.97 h 0.06 v 7.92 c 1.72,80.12 67.05,144.58 147.61,144.58 h 190.77 c 14.86,0 26.92,12.05 26.92,26.92 v 441.84 c 0,13.13 -10.63,23.77 -23.78,23.77"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

96
Assets/JoplinLetter.eps Normal file
View File

@@ -0,0 +1,96 @@
%!PS-Adobe-3.0 EPSF-3.0
%%Creator: cairo 1.15.6 (http://cairographics.org)
%%CreationDate: Wed Dec 04 10:22:47 2019
%%Pages: 1
%%DocumentData: Clean7Bit
%%LanguageLevel: 2
%%BoundingBox: 0 0 331 372
%%EndComments
%%BeginProlog
save
50 dict begin
/q { gsave } bind def
/Q { grestore } bind def
/cm { 6 array astore concat } bind def
/w { setlinewidth } bind def
/J { setlinecap } bind def
/j { setlinejoin } bind def
/M { setmiterlimit } bind def
/d { setdash } bind def
/m { moveto } bind def
/l { lineto } bind def
/c { curveto } bind def
/h { closepath } bind def
/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
0 exch rlineto 0 rlineto closepath } bind def
/S { stroke } bind def
/f { fill } bind def
/f* { eofill } bind def
/n { newpath } bind def
/W { clip } bind def
/W* { eoclip } bind def
/BT { } bind def
/ET { } bind def
/pdfmark where { pop globaldict /?pdfmark /exec load put }
{ globaldict begin /?pdfmark /pop load def /pdfmark
/cleartomark load def end } ifelse
/BDC { mark 3 1 roll /BDC pdfmark } bind def
/EMC { mark /EMC pdfmark } bind def
/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
/Tj { show currentpoint cairo_store_point } bind def
/TJ {
{
dup
type /stringtype eq
{ show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
} forall
currentpoint cairo_store_point
} bind def
/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
/Tf { pop /cairo_font exch def /cairo_font_matrix where
{ pop cairo_selectfont } if } bind def
/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
/cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
/cairo_font where { pop cairo_selectfont } if } bind def
/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
/g { setgray } bind def
/rg { setrgbcolor } bind def
/d1 { setcachedevice } bind def
/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def
/cairo_image { image cairo_flush_ascii85_file } def
/cairo_imagemask { imagemask cairo_flush_ascii85_file } def
%%EndProlog
%%BeginSetup
%%EndSetup
%%Page: 1 1
%%BeginPageSetup
%%PageBoundingBox: 0 0 331 372
%%EndPageSetup
q 0 0 331 372 rectclip
1 0 0 -1 0 372 cm q
0 g
116.223 371.219 m 92.629 368.047 79.551 364.387 63.867 356.57 c 34.902
342.121 12.555 317.016 3.848 289.133 c 0.383 278.039 -0.012 275.32 0 262.508
c 0.008 251.938 0.258 249.27 1.699 244.234 c 4.723 233.676 8.77 226.742
16.426 219.008 c 25.66 209.676 35.293 205.477 48.723 204.93 c 61.566 204.41
70.113 206.629 78.211 212.594 c 83.371 216.391 88.637 223.828 91.578 231.484
c 93.445 236.34 93.59 237.676 94.133 255.008 c 94.699 273.145 95.164 276.641
98.078 284.684 c 102.059 295.672 108.82 303.285 118.855 308.086 c 127.93
312.426 134.84 313.762 146.094 313.348 c 153.41 313.078 156.309 312.625
160.699 311.07 c 173.777 306.434 184.691 296.008 189.934 283.133 c 195.355
269.828 195.344 270.066 195.328 160.883 c 195.313 65.117 195.297 64.098
193.781 60.758 c 190.078 52.586 186.18 51.125 166.371 50.488 c 151.848
50.02 l 151.848 0 l 329.973 0.383 l 330.168 25.199 l 330.367 50.02 l 315.918
50.527 l 307.902 50.809 300.027 51.465 298.23 52.004 c 293.328 53.461 290.211
56.363 288.234 61.305 c 286.504 65.633 l 286.027 164.258 l 285.547 264.215
285.48 266.555 282.668 280.234 c 277.531 305.25 259.137 330.953 234.594
347.406 c 214.891 360.621 193.523 367.852 164.223 371.227 c 156.445 372.121
122.898 372.117 116.223 371.219 c h
116.223 371.219 m f
Q Q
showpage
%%Trailer
end restore
%%EOF

BIN
Assets/JoplinLetter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
@@ -9,54 +7,63 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="116.54575mm"
height="131.19589mm"
viewBox="0 0 116.54575 131.19589"
viewBox="0 0 682.66669 682.66669"
height="682.66669"
width="682.66669"
xml:space="preserve"
id="svg2"
version="1.1"
id="svg8"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
sodipodi:docname="JoplinLetter.svg">
sodipodi:docname="JoplinLetter.svg"
inkscape:version="1.0beta1 (32d4812, 2019-09-19)"><metadata
id="metadata23">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
inkscape:document-rotation="0"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1600"
inkscape:window-height="907"
id="namedview21"
showgrid="false"
inkscape:zoom="0.35"
inkscape:cx="400"
inkscape:cy="560"
inkscape:window-x="0"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:current-layer="svg2" />
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.49497475"
inkscape:cx="152.11122"
inkscape:cy="-26.090631"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-2.7903623,-2.175533)">
<path
style="fill:#000000;stroke-width:0.26458332"
d="m 43.790458,133.13317 c -8.32317,-1.11843 -12.937,-2.40956 -18.46857,-5.16822 -10.21924,-5.09644 -18.1023498,-13.95338 -21.1745998,-23.79038 -1.22214,-3.91319 -1.3607,-4.872332 -1.35685,-9.392712 0.003,-3.72804 0.0907,-4.66941 0.59927,-6.44569 1.0664,-3.7246 2.49409,-6.1704 5.19529,-8.90014 3.2574198,-3.29184 6.6565798,-4.77332 11.3929598,-4.96548 4.53189,-0.18388 7.54661,0.59927 10.40386,2.70266 1.82035,1.34007 3.67693,3.96421 4.71565,6.66525 0.65839,1.71204 0.70959,2.1839 0.90042,8.29756 0.19973,6.39855 0.36372,7.6318 1.39223,10.469902 1.40468,3.87611 3.78939,6.56189 7.33039,8.25588 3.20047,1.53108 5.63801,2.00183 9.60817,1.8556 2.58182,-0.0951 3.60332,-0.25442 5.15337,-0.80371 4.61358,-1.63493 8.46322,-5.31381 10.31326,-9.85579 1.91154,-4.693002 1.90785,-4.609372 1.90213,-43.127082 -0.005,-33.78395 -0.0106,-34.14337 -0.54484,-35.32188 -1.30698,-2.882895 -2.68223,-3.398165 -9.66971,-3.622945 l -5.12472,-0.16486 V 10.998334 2.175533 l 31.41927,0.06723 31.419272,0.06723 0.0697,8.755726 0.0697,8.755724 -5.09675,0.1793 c -2.82759,0.0995 -5.60596,0.33101 -6.24051,0.52006 -1.72896,0.5151 -2.82899,1.538795 -3.52569,3.281045 l -0.61059,1.5269 -0.16762,34.7927 c -0.16988,35.26321 -0.19381,36.08914 -1.18496,40.914372 -1.81292,8.82581 -8.301582,17.89221 -16.959672,23.69719 -6.95182,4.66099 -14.48972,7.21214 -24.82645,8.40235 -2.7431,0.31585 -14.57797,0.31433 -16.93333,-0.002 z"
id="path21"
inkscape:connector-curvature="0" />
</g>
id="defs6" />
<path
id="path30"
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.133333;stop-opacity:1"
d="M 528.21199,91.302685 H 342.69066 c -1.75334,0 -3.17067,1.418666 -3.17067,3.169333 v 58.912002 c 0,1.98266 1.60533,3.58933 3.58933,3.58933 h 25.436 c 10.288,0 18.63067,7.91333 19.524,17.96933 v 40.39067 22.50266 214.33067 1.51866 h -0.007 c 0.064,2.24534 -0.0253,4.45334 -0.244,6.628 -0.024,0.31734 -0.0667,0.63067 -0.10534,0.94534 -0.14666,1.27066 -0.30933,2.53466 -0.556,3.772 -0.13466,0.70533 -0.32533,1.392 -0.49466,2.08666 -0.228,0.924 -0.412,1.86267 -0.696,2.76667 -1.67734,5.36933 -4.32934,10.34933 -7.99734,14.73333 -0.13466,0.156 -0.30133,0.3 -0.43466,0.45467 -1.11867,1.296 -2.29334,2.55866 -3.59334,3.74133 -1.312,1.19333 -2.70133,2.30267 -4.16133,3.33333 -10.37867,7.352 -24.348,10.58667 -39.956,9.09334 -19.90133,-1.87067 -39.64533,-10.896 -55.604,-25.416 -15.956,-14.51867 -25.87733,-32.48267 -27.93066,-50.588 -1.84667,-16.19733 3.00666,-30.45067 13.656,-40.14 0.028,-0.0213 0.0533,-0.0413 0.0747,-0.064 0.412,-0.36933 0.86534,-0.69333 1.28934,-1.04933 7.62133,-6.38534 17.556,-10.25467 28.89333,-11.32134 0.128,-0.012 0.25067,-0.032 0.372,-0.0427 1.19333,-0.10534 2.40933,-0.15334 3.636,-0.19867 0.64133,-0.0213 1.27467,-0.0667 1.92533,-0.072 0.216,-0.003 0.42134,-0.0253 0.63734,-0.0253 0.38666,0 0.788,0.0507 1.17466,0.056 1.78667,0.028 3.58667,0.10133 5.42267,0.25866 0.232,0.0187 0.45333,0.0107 0.692,0.032 0.16933,0.0173 0.33733,0.0547 0.50667,0.072 10.4,1.04267 20.69733,4.148 30.46933,8.85334 0.204,0.009 0.44,0.072 0.73466,0.23466 2.97867,1.64534 3.54934,-0.12 3.63734,-1.28666 V 329.57734 291.868 c 0,-2.54 -1.76667,-4.78666 -4.244,-5.332 -52.63467,-11.584 -104.27733,0.47334 -140.71733,33.64534 -31.83333,28.95733 -47.232,70.74399 -42.24267,114.63866 4.452,39.09733 24.52134,76.65866 56.51733,105.77733 31.18534,28.372 70.892,46.11467 111.85067,49.97347 5.644,0.5224 11.31467,0.79173 16.848,0.79173 39.11733,0 75.41466,-13.41307 102.20533,-37.78387 25.37867,-23.10666 40.58,-54.836 42.81066,-89.35466 l 0.20667,-226.388 h 0.0227 v -60.52933 h 0.008 v -1.056 c 0.22933,-10.68266 8.94,-19.27733 19.68133,-19.27733 h 25.436 c 1.98133,0 3.58933,-1.60667 3.58933,-3.58933 V 94.472018 c 0,-1.750667 -1.41733,-3.169333 -3.17066,-3.169333"
inkscape:connector-curvature="0" />
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 B

After

Width:  |  Height:  |  Size: 697 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
Assets/SquareIcon1024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
Assets/SquareIcon512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -3,6 +3,7 @@
# General information
- All the applications share the same library, which, for historical reasons, is in ReactNativeClient/lib. This library is copied to the relevant directories when building each app.
- In general, most of the backend (anything to do with the database, synchronisation, data import or export, etc.) is shared across all the apps, so when making a change please consider how it will affect all the apps.
## macOS dependencies
@@ -18,11 +19,10 @@
# Building the tools
Before building any of the applications, you need to build the tools:
Before building any of the applications, you need to build the tools and pre-commit hooks:
```
cd Tools
npm install
npm install && cd Tools && npm install
```
# Building the Electron application
@@ -65,7 +65,7 @@ The [building\_win32\_tips on this page](./readme/building_win32_tips.md) might
# Building the Mobile application
First you need to setup React Native to build projects with native code. For this, follow the instructions on the [Get Started](https://facebook.github.io/react-native/docs/getting-started.html) tutorial, in the "Building Projects with Native Code" tab.
First you need to setup React Native to build projects with native code. For this, follow the instructions on the [Get Started](https://facebook.github.io/react-native/docs/getting-started.html) tutorial, in the "React Native CLI Quickstart" tab.
Then, from `/ReactNativeClient`, run `npm install`, then `react-native run-ios` or `react-native run-android`.
@@ -78,4 +78,4 @@ npm install
rsync --delete -aP ../ReactNativeClient/locales/ build/locales/
```
Run `run.sh` to start the application for testing.
Run `run.sh` to start the application for testing.

View File

@@ -32,7 +32,8 @@ Joplin is available in multiple languages thanks to the help of its users. You c
If you want to start contributing to the project's code, please follow these guidelines before creating a pull request:
- Bug fixes are always welcome. Start by reviewing the list of [essential issues](https://github.com/laurent22/joplin/issues?q=is%3Aissue+is%3Aopen+label%3Aessential)
- Bug fixes are always welcome. Start by reviewing the [list of bugs](https://github.com/laurent22/joplin/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
- A good way to easily start contributing is to pick and work on a [good first issue](https://github.com/laurent22/joplin/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22). We try to make these issues as clear as possible and provide basic info on how the code should be changed, and if something is unclear feel free to ask for more information on the issue.
- Before adding a new feature, ask about it in the [Github Issue Tracker](https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&q=is%3Aissue) or the [Joplin Forum](https://discourse.joplinapp.org/), or check if existing discussions exist to make sure the new functionality is desired.
- **Changes that will consist in more than 50 lines of code should be discussed the [Joplin Forum](https://discourse.joplinapp.org/)**, so that you don't spend too much time implementing something that might not be accepted.
@@ -40,10 +41,7 @@ Building the apps is relatively easy - please [see the build instructions](https
## Coding style
There are only two rules, but not following them means the pull request will not be accepted (it can be accepted once the issues are fixed):
- **Please use tabs, NOT spaces.**
- **Please do not add or remove optional characters, such as spaces or colons.** Please setup your editor so that it only changes what you are working on and is not making automated changes elsewhere. The reason for this is that small white space changes make diff hard to read and can cause needless conflicts.
Coding style is enforced by a pre-commit hook that runs eslint. This hook is installed whenever running `npm install` on any of the application directory. If for some reason the pre-commit hook didn't get installed, you can manually install it by running `npm install` at the root of the repository.
## Unit tests
@@ -54,10 +52,23 @@ The tests are under CliClient/tests. To get them running, you first need to buil
cd CliClient
npm i
Then to run all the test units:
To run the test units, you must have an instance of the cli app running. In a first window navigate into `CliClient` and run:
```sh
./run.sh
```
> If you get an error like `Error: Cannot find module '../locales/index.js'`, this means you must (a) rebuild translations or (b) take > them from one of the other apps. To do option b, you can run the following command to copy them from the `ReactNativeClient` directory:>
>
> ```sh
> cd .. # Return to the root of the project
> rsync -aP ./ReactNativeClient/locales/ ./CliClient/build/locales/
> ```
Then run the tests in a second window. To run all the test units:
./run_test.sh
To run just one particular file:
./run_test.sh markdownUtils # Don't add the .js extension
./run_test.sh markdownUtils # Don't add the .js extension

13
CliClient/.eslintrc.js Normal file
View File

@@ -0,0 +1,13 @@
module.exports = {
"overrides": [
{
"files": ["tests/**/*.js"],
'rules': {
// Ignore all unused function arguments, because in some
// case they are kept to indicate the function signature.
"no-unused-vars": ["error", { "argsIgnorePattern": ".*" }],
"@typescript-eslint/no-unused-vars": 0,
}
},
],
};

View File

@@ -1,14 +1,11 @@
const { _ } = require('lib/locale.js');
const { Logger } = require('lib/logger.js');
const Resource = require('lib/models/Resource.js');
const { netUtils } = require('lib/net-utils.js');
const http = require("http");
const urlParser = require("url");
const http = require('http');
const urlParser = require('url');
const enableServerDestroy = require('server-destroy');
class ResourceServer {
constructor() {
this.server_ = null;
this.logger_ = new Logger();
@@ -31,7 +28,7 @@ class ResourceServer {
baseUrl() {
if (!this.port_) return '';
return 'http://127.0.0.1:' + this.port_;
return `http://127.0.0.1:${this.port_}`;
}
setLinkHandler(handler) {
@@ -40,7 +37,7 @@ class ResourceServer {
async start() {
this.port_ = await netUtils.findAvailablePort([9167, 9267, 8167, 8267]);
if (!this.port_) {
if (!this.port_) {
this.logger().error('Could not find available port to start resource server. Please report the error at https://github.com/laurent22/joplin');
return;
}
@@ -48,16 +45,15 @@ class ResourceServer {
this.server_ = http.createServer();
this.server_.on('request', async (request, response) => {
const writeResponse = (message) => {
const writeResponse = message => {
response.write(message);
response.end();
}
};
const url = urlParser.parse(request.url, true);
let resourceId = url.pathname.split('/');
if (resourceId.length < 2) {
writeResponse('Error: could not get resource ID from path name: ' + url.pathname);
writeResponse(`Error: could not get resource ID from path name: ${url.pathname}`);
return;
}
resourceId = resourceId[1];
@@ -66,9 +62,10 @@ class ResourceServer {
try {
const done = await this.linkHandler_(resourceId, response);
if (!done) throw new Error('Unhandled resource: ' + resourceId);
if (!done) throw new Error(`Unhandled resource: ${resourceId}`);
} catch (error) {
response.setHeader('Content-Type', 'text/plain');
// eslint-disable-next-line require-atomic-updates
response.statusCode = 400;
response.write(error.message);
}
@@ -76,7 +73,7 @@ class ResourceServer {
response.end();
});
this.server_.on('error', (error) => {
this.server_.on('error', error => {
this.logger().error('Resource server:', error);
});
@@ -91,7 +88,6 @@ class ResourceServer {
if (this.server_) this.server_.destroy();
this.server_ = null;
}
}
module.exports = ResourceServer;
module.exports = ResourceServer;

View File

@@ -5,13 +5,12 @@ const Tag = require('lib/models/Tag.js');
const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js');
const Resource = require('lib/models/Resource.js');
const { cliUtils } = require('./cli-utils.js');
const { reducer, defaultState } = require('lib/reducer.js');
const { splitCommandString } = require('lib/string-utils.js');
const { reg } = require('lib/registry.js');
const { _ } = require('lib/locale.js');
const Entities = require('html-entities').AllHtmlEntities;
const htmlentities = (new Entities()).encode;
const htmlentities = new Entities().encode;
const chalk = require('chalk');
const tk = require('terminal-kit');
@@ -20,12 +19,10 @@ const Renderer = require('tkwidgets/framework/Renderer.js');
const DecryptionWorker = require('lib/services/DecryptionWorker');
const BaseWidget = require('tkwidgets/BaseWidget.js');
const ListWidget = require('tkwidgets/ListWidget.js');
const TextWidget = require('tkwidgets/TextWidget.js');
const HLayoutWidget = require('tkwidgets/HLayoutWidget.js');
const VLayoutWidget = require('tkwidgets/VLayoutWidget.js');
const ReduxRootWidget = require('tkwidgets/ReduxRootWidget.js');
const RootWidget = require('tkwidgets/RootWidget.js');
const WindowWidget = require('tkwidgets/WindowWidget.js');
const NoteWidget = require('./gui/NoteWidget.js');
@@ -37,7 +34,6 @@ const StatusBarWidget = require('./gui/StatusBarWidget.js');
const ConsoleWidget = require('./gui/ConsoleWidget.js');
class AppGui {
constructor(app, store, keymap) {
try {
this.app_ = app;
@@ -50,12 +46,12 @@ class AppGui {
// Some keys are directly handled by the tkwidget framework
// so they need to be remapped in a different way.
this.tkWidgetKeys_ = {
'focus_next': 'TAB',
'focus_previous': 'SHIFT_TAB',
'move_up': 'UP',
'move_down': 'DOWN',
'page_down': 'PAGE_DOWN',
'page_up': 'PAGE_UP',
focus_next: 'TAB',
focus_previous: 'SHIFT_TAB',
move_up: 'UP',
move_down: 'DOWN',
page_down: 'PAGE_DOWN',
page_up: 'PAGE_UP',
};
this.renderer_ = null;
@@ -64,7 +60,7 @@ class AppGui {
this.renderer_ = new Renderer(this.term(), this.rootWidget_);
this.app_.on('modelAction', async (event) => {
this.app_.on('modelAction', async event => {
await this.handleModelAction(event.action);
});
@@ -83,7 +79,7 @@ class AppGui {
reg.setupRecurrentSync();
DecryptionWorker.instance().scheduleStart();
} catch (error) {
this.fullScreen(false);
if (this.term_) { this.fullScreen(false); }
console.error(error);
process.exit(1);
}
@@ -134,7 +130,7 @@ class AppGui {
};
folderList.name = 'folderList';
folderList.vStretch = true;
folderList.on('currentItemChange', async (event) => {
folderList.on('currentItemChange', async event => {
const item = folderList.currentItem;
if (item === '-') {
@@ -169,7 +165,7 @@ class AppGui {
});
}
});
this.rootWidget_.connect(folderList, (state) => {
this.rootWidget_.connect(folderList, state => {
return {
selectedFolderId: state.selectedFolderId,
selectedTagId: state.selectedTagId,
@@ -196,7 +192,7 @@ class AppGui {
id: note ? note.id : null,
});
});
this.rootWidget_.connect(noteList, (state) => {
this.rootWidget_.connect(noteList, state => {
return {
selectedNoteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
items: state.notes,
@@ -210,7 +206,7 @@ class AppGui {
borderBottomWidth: 1,
borderLeftWidth: 1,
};
this.rootWidget_.connect(noteText, (state) => {
this.rootWidget_.connect(noteText, state => {
return {
noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
notes: state.notes,
@@ -225,7 +221,7 @@ class AppGui {
borderLeftWidth: 1,
borderRightWidth: 1,
};
this.rootWidget_.connect(noteMetadata, (state) => {
this.rootWidget_.connect(noteMetadata, state => {
return { noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null };
});
noteMetadata.hide();
@@ -292,7 +288,7 @@ class AppGui {
if (!cmd) return;
const isConfigPassword = cmd.indexOf('config ') >= 0 && cmd.indexOf('password') >= 0;
if (isConfigPassword) return;
this.stdout(chalk.cyan.bold('> ' + cmd));
this.stdout(chalk.cyan.bold(`> ${cmd}`));
}
setupKeymap(keymap) {
@@ -301,7 +297,7 @@ class AppGui {
for (let i = 0; i < keymap.length; i++) {
const item = Object.assign({}, keymap[i]);
if (!item.command) throw new Error('Missing command for keymap item: ' + JSON.stringify(item));
if (!item.command) throw new Error(`Missing command for keymap item: ${JSON.stringify(item)}`);
if (!('type' in item)) item.type = 'exec';
@@ -408,7 +404,7 @@ class AppGui {
activeListItem() {
const widget = this.widget('mainWindow').focusedWidget;
if (!widget) return null;
if (widget.name == 'noteList' || widget.name == 'folderList') {
return widget.currentItem;
}
@@ -430,25 +426,21 @@ class AppGui {
}
async processFunctionCommand(cmd) {
if (cmd === 'activate') {
const w = this.widget('mainWindow').focusedWidget;
if (w.name === 'folderList') {
this.widget('noteList').focus();
} else if (w.name === 'noteList' || w.name === 'noteText') {
this.processPromptCommand('edit $n');
}
} else if (cmd === 'delete') {
if (this.widget('folderList').hasFocus) {
const item = this.widget('folderList').selectedJoplinItem;
if (!item) return;
if (item.type_ === BaseModel.TYPE_FOLDER) {
await this.processPromptCommand('rmbook ' + item.id);
await this.processPromptCommand(`rmbook ${item.id}`);
} else if (item.type_ === BaseModel.TYPE_TAG) {
this.stdout(_('To delete a tag, untag the associated notes.'));
} else if (item.type_ === BaseModel.TYPE_SEARCH) {
@@ -462,9 +454,7 @@ class AppGui {
} else {
this.stdout(_('Please select the note or notebook to be deleted first.'));
}
} else if (cmd === 'toggle_console') {
if (!this.consoleIsShown()) {
this.showConsole();
this.minimizeConsole();
@@ -475,22 +465,15 @@ class AppGui {
this.maximizeConsole();
}
}
} else if (cmd === 'toggle_metadata') {
this.toggleNoteMetadata();
} else if (cmd === 'enter_command_line_mode') {
const cmd = await this.widget('statusBar').prompt();
if (!cmd) return;
this.addCommandToConsole(cmd);
await this.processPromptCommand(cmd);
await this.processPromptCommand(cmd);
} else {
throw new Error('Unknown command: ' + cmd);
throw new Error(`Unknown command: ${cmd}`);
}
}
@@ -501,7 +484,7 @@ class AppGui {
// this.logger().debug('Got command: ' + cmd);
try {
try {
let note = this.widget('noteList').currentItem;
let folder = this.widget('folderList').currentItem;
let args = splitCommandString(cmd);
@@ -511,7 +494,7 @@ class AppGui {
args[i] = note ? note.id : '';
} else if (args[i] == '$b') {
args[i] = folder ? folder.id : '';
} else if (args[i] == '$c') {
} else if (args[i] == '$c') {
const item = this.activeListItem();
args[i] = item ? item.id : '';
}
@@ -523,7 +506,7 @@ class AppGui {
}
this.widget('console').scrollBottom();
// Invalidate so that the screen is redrawn in case inputting a command has moved
// the GUI up (in particular due to autocompletion), it's moved back to the right position.
this.widget('root').invalidate();
@@ -603,17 +586,17 @@ class AppGui {
async setupResourceServer() {
const linkStyle = chalk.blue.underline;
const noteTextWidget = this.widget('noteText');
const resourceIdRegex = /^:\/[a-f0-9]+$/i
const resourceIdRegex = /^:\/[a-f0-9]+$/i;
const noteLinks = {};
const hasProtocol = function(s, protocols) {
if (!s) return false;
s = s.trim().toLowerCase();
for (let i = 0; i < protocols.length; i++) {
if (s.indexOf(protocols[i] + '://') === 0) return true;
if (s.indexOf(`${protocols[i]}://`) === 0) return true;
}
return false;
}
};
// By default, before the server is started, only the regular
// URLs appear in blue.
@@ -637,29 +620,31 @@ class AppGui {
const link = noteLinks[path];
if (link.type === 'url') {
response.writeHead(302, { 'Location': link.url });
response.writeHead(302, { Location: link.url });
return true;
}
if (link.type === 'item') {
const itemId = link.id;
let item = await BaseItem.loadItemById(itemId);
if (!item) throw new Error('No item with ID ' + itemId); // Should be nearly impossible
if (!item) throw new Error(`No item with ID ${itemId}`); // Should be nearly impossible
if (item.type_ === BaseModel.TYPE_RESOURCE) {
if (item.mime) response.setHeader('Content-Type', item.mime);
response.write(await Resource.content(item));
} else if (item.type_ === BaseModel.TYPE_NOTE) {
const html = [`
const html = [
`
<!DOCTYPE html>
<html class="client-nojs" lang="en" dir="ltr">
<head><meta charset="UTF-8"/></head><body>
`];
html.push('<pre>' + htmlentities(item.title) + '\n\n' + htmlentities(item.body) + '</pre>');
`,
];
html.push(`<pre>${htmlentities(item.title)}\n\n${htmlentities(item.body)}</pre>`);
html.push('</body></html>');
response.write(html.join(''));
} else {
throw new Error('Unsupported item type: ' + item.type_);
throw new Error(`Unsupported item type: ${item.type_}`);
}
return true;
@@ -679,7 +664,7 @@ class AppGui {
noteLinks[index] = {
type: 'item',
id: url.substr(2),
};
};
} else if (hasProtocol(url, ['http', 'https', 'file', 'ftp'])) {
noteLinks[index] = {
type: 'url',
@@ -691,7 +676,7 @@ class AppGui {
return url;
}
return linkStyle(this.resourceServer_.baseUrl() + '/' + index);
return linkStyle(`${this.resourceServer_.baseUrl()}/${index}`);
},
};
}
@@ -710,8 +695,7 @@ class AppGui {
term.grabInput();
term.on('key', async (name, matches, data) => {
term.on('key', async (name) => {
// -------------------------------------------------------------------------
// Handle special shortcuts
// -------------------------------------------------------------------------
@@ -729,13 +713,13 @@ class AppGui {
return;
}
if (name === 'CTRL_C' ) {
if (name === 'CTRL_C') {
const cmd = this.app().currentCommand();
if (!cmd || !cmd.cancellable() || this.commandCancelCalled_) {
this.stdout(_('Press Ctrl+D or type "exit" to exit the application'));
} else {
this.commandCancelCalled_ = true;
await cmd.cancel()
await cmd.cancel();
this.commandCancelCalled_ = false;
}
return;
@@ -744,8 +728,8 @@ class AppGui {
// -------------------------------------------------------------------------
// Build up current shortcut
// -------------------------------------------------------------------------
const now = (new Date()).getTime();
const now = new Date().getTime();
if (now - this.lastShortcutKeyTime_ > 800 || this.isSpecialKey(name)) {
this.currentShortcutKeys_ = [name];
@@ -793,7 +777,7 @@ class AppGui {
} else if (keymapItem.type === 'tkwidgets') {
this.widget('root').handleKey(this.tkWidgetKeys_[keymapItem.command]);
} else {
throw new Error('Unknown command type: ' + JSON.stringify(keymapItem));
throw new Error(`Unknown command type: ${JSON.stringify(keymapItem)}`);
}
}
@@ -813,7 +797,6 @@ class AppGui {
process.exit(1);
});
}
}
AppGui.INPUT_MODE_NORMAL = 1;

View File

@@ -1,10 +1,5 @@
const { BaseApplication } = require('lib/BaseApplication');
const { createStore, applyMiddleware } = require('redux');
const { reducer, defaultState } = require('lib/reducer.js');
const { JoplinDatabase } = require('lib/joplin-database.js');
const { Database } = require('lib/database.js');
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
const { DatabaseDriverNode } = require('lib/database-driver-node.js');
const ResourceService = require('lib/services/ResourceService');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
@@ -12,21 +7,15 @@ const BaseItem = require('lib/models/BaseItem.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
const Setting = require('lib/models/Setting.js');
const { Logger } = require('lib/logger.js');
const { sprintf } = require('sprintf-js');
const { reg } = require('lib/registry.js');
const { fileExtension } = require('lib/path-utils.js');
const { shim } = require('lib/shim.js');
const { _, setLocale, defaultLocale, closestSupportedLocale } = require('lib/locale.js');
const os = require('os');
const { _ } = require('lib/locale.js');
const fs = require('fs-extra');
const { cliUtils } = require('./cli-utils.js');
const Cache = require('lib/Cache');
const WelcomeUtils = require('lib/WelcomeUtils');
const RevisionService = require('lib/services/RevisionService');
class Application extends BaseApplication {
constructor() {
super();
@@ -75,7 +64,7 @@ class Application extends BaseApplication {
// const response = await cliUtils.promptMcq(msg, answers);
// if (!response) return null;
return output[response - 1];
// return output[response - 1];
} else {
return output.length ? output[0] : null;
}
@@ -97,10 +86,12 @@ class Application extends BaseApplication {
const parent = options.parent ? options.parent : app().currentFolder();
const ItemClass = BaseItem.itemClass(type);
if (type == BaseModel.TYPE_NOTE && pattern.indexOf('*') >= 0) { // Handle it as pattern
if (type == BaseModel.TYPE_NOTE && pattern.indexOf('*') >= 0) {
// Handle it as pattern
if (!parent) throw new Error(_('No notebook selected.'));
return await Note.previews(parent.id, { titlePattern: pattern });
} else { // Single item
} else {
// Single item
let item = null;
if (type == BaseModel.TYPE_NOTE) {
if (!parent) throw new Error(_('No notebook has been specified.'));
@@ -126,15 +117,15 @@ class Application extends BaseApplication {
}
setupCommand(cmd) {
cmd.setStdout((text) => {
cmd.setStdout(text => {
return this.stdout(text);
});
cmd.setDispatcher((action) => {
cmd.setDispatcher(action => {
if (this.store()) {
return this.store().dispatch(action);
} else {
return (action) => {};
return () => {};
}
});
@@ -145,10 +136,10 @@ class Application extends BaseApplication {
if (!options.answers) options.answers = options.booleanAnswerDefault === 'y' ? [_('Y'), _('n')] : [_('N'), _('y')];
if (options.type == 'boolean') {
message += ' (' + options.answers.join('/') + ')';
message += ` (${options.answers.join('/')})`;
}
let answer = await this.gui().prompt('', message + ' ', options);
let answer = await this.gui().prompt('', `${message} `, options);
if (options.type === 'boolean') {
if (answer === null) return false; // Pressed ESCAPE
@@ -185,12 +176,12 @@ class Application extends BaseApplication {
commands(uiType = null) {
if (!this.allCommandsLoaded_) {
fs.readdirSync(__dirname).forEach((path) => {
fs.readdirSync(__dirname).forEach(path => {
if (path.indexOf('command-') !== 0) return;
const ext = fileExtension(path)
const ext = fileExtension(path);
if (ext != 'js') return;
let CommandClass = require('./' + path);
let CommandClass = require(`./${path}`);
let cmd = new CommandClass();
if (!cmd.enabled()) return;
cmd = this.setupCommand(cmd);
@@ -257,7 +248,7 @@ class Application extends BaseApplication {
let CommandClass = null;
try {
CommandClass = require(__dirname + '/command-' + name + '.js');
CommandClass = require(`${__dirname}/command-${name}.js`);
} catch (error) {
if (error.message && error.message.indexOf('Cannot find module') >= 0) {
let e = new Error(_('No such command: %s', name));
@@ -276,19 +267,27 @@ class Application extends BaseApplication {
dummyGui() {
return {
isDummy: () => { return true; },
prompt: (initialText = '', promptString = '', options = null) => { return cliUtils.prompt(initialText, promptString, options); },
isDummy: () => {
return true;
},
prompt: (initialText = '', promptString = '', options = null) => {
return cliUtils.prompt(initialText, promptString, options);
},
showConsole: () => {},
maximizeConsole: () => {},
stdout: (text) => { console.info(text); },
fullScreen: (b=true) => {},
stdout: text => {
console.info(text);
},
fullScreen: () => {},
exit: () => {},
showModalOverlay: (text) => {},
showModalOverlay: () => {},
hideModalOverlay: () => {},
stdoutMaxWidth: () => { return 100; },
stdoutMaxWidth: () => {
return 100;
},
forceRender: () => {},
termSaveState: () => {},
termRestoreState: (state) => {},
termRestoreState: () => {},
};
}
@@ -300,7 +299,7 @@ class Application extends BaseApplication {
let outException = null;
try {
if (this.gui().isDummy() && !this.activeCommand_.supportsUi('cli')) throw new Error(_('The command "%s" is only available in GUI mode', this.activeCommand_.name()));
if (this.gui().isDummy() && !this.activeCommand_.supportsUi('cli')) throw new Error(_('The command "%s" is only available in GUI mode', this.activeCommand_.name()));
const cmdArgs = cliUtils.makeCommandArgs(this.activeCommand_, argv);
await this.activeCommand_.action(cmdArgs);
} catch (error) {
@@ -316,24 +315,24 @@ class Application extends BaseApplication {
async loadKeymaps() {
const defaultKeyMap = [
{ "keys": [":"], "type": "function", "command": "enter_command_line_mode" },
{ "keys": ["TAB"], "type": "function", "command": "focus_next" },
{ "keys": ["SHIFT_TAB"], "type": "function", "command": "focus_previous" },
{ "keys": ["UP"], "type": "function", "command": "move_up" },
{ "keys": ["DOWN"], "type": "function", "command": "move_down" },
{ "keys": ["PAGE_UP"], "type": "function", "command": "page_up" },
{ "keys": ["PAGE_DOWN"], "type": "function", "command": "page_down" },
{ "keys": ["ENTER"], "type": "function", "command": "activate" },
{ "keys": ["DELETE", "BACKSPACE"], "type": "function", "command": "delete" },
{ "keys": [" "], "command": "todo toggle $n" },
{ "keys": ["tc"], "type": "function", "command": "toggle_console" },
{ "keys": ["tm"], "type": "function", "command": "toggle_metadata" },
{ "keys": ["/"], "type": "prompt", "command": "search \"\"", "cursorPosition": -2 },
{ "keys": ["mn"], "type": "prompt", "command": "mknote \"\"", "cursorPosition": -2 },
{ "keys": ["mt"], "type": "prompt", "command": "mktodo \"\"", "cursorPosition": -2 },
{ "keys": ["mb"], "type": "prompt", "command": "mkbook \"\"", "cursorPosition": -2 },
{ "keys": ["yn"], "type": "prompt", "command": "cp $n \"\"", "cursorPosition": -2 },
{ "keys": ["dn"], "type": "prompt", "command": "mv $n \"\"", "cursorPosition": -2 }
{ keys: [':'], type: 'function', command: 'enter_command_line_mode' },
{ keys: ['TAB'], type: 'function', command: 'focus_next' },
{ keys: ['SHIFT_TAB'], type: 'function', command: 'focus_previous' },
{ keys: ['UP'], type: 'function', command: 'move_up' },
{ keys: ['DOWN'], type: 'function', command: 'move_down' },
{ keys: ['PAGE_UP'], type: 'function', command: 'page_up' },
{ keys: ['PAGE_DOWN'], type: 'function', command: 'page_down' },
{ keys: ['ENTER'], type: 'function', command: 'activate' },
{ keys: ['DELETE', 'BACKSPACE'], type: 'function', command: 'delete' },
{ keys: [' '], command: 'todo toggle $n' },
{ keys: ['tc'], type: 'function', command: 'toggle_console' },
{ keys: ['tm'], type: 'function', command: 'toggle_metadata' },
{ keys: ['/'], type: 'prompt', command: 'search ""', cursorPosition: -2 },
{ keys: ['mn'], type: 'prompt', command: 'mknote ""', cursorPosition: -2 },
{ keys: ['mt'], type: 'prompt', command: 'mktodo ""', cursorPosition: -2 },
{ keys: ['mb'], type: 'prompt', command: 'mkbook ""', cursorPosition: -2 },
{ keys: ['yn'], type: 'prompt', command: 'cp $n ""', cursorPosition: -2 },
{ keys: ['dn'], type: 'prompt', command: 'mv $n ""', cursorPosition: -2 },
];
// Filter the keymap item by command so that items in keymap.json can override
@@ -341,10 +340,10 @@ class Application extends BaseApplication {
const itemsByCommand = {};
for (let i = 0; i < defaultKeyMap.length; i++) {
itemsByCommand[defaultKeyMap[i].command] = defaultKeyMap[i]
itemsByCommand[defaultKeyMap[i].command] = defaultKeyMap[i];
}
const filePath = Setting.value('profileDir') + '/keymap.json';
const filePath = `${Setting.value('profileDir')}/keymap.json`;
if (await fs.pathExists(filePath)) {
try {
let configString = await fs.readFile(filePath, 'utf-8');
@@ -356,7 +355,7 @@ class Application extends BaseApplication {
}
} catch (error) {
let msg = error.message ? error.message : '';
msg = 'Could not load keymap ' + filePath + '\n' + msg;
msg = `Could not load keymap ${filePath}\n${msg}`;
error.message = msg;
throw error;
}
@@ -368,13 +367,25 @@ class Application extends BaseApplication {
output.push(itemsByCommand[n]);
}
// Map reserved shortcuts to their equivalent key
// https://github.com/cronvel/terminal-kit/issues/101
for (let i = 0; i < output.length; i++) {
const newKeys = output[i].keys.map(k => {
k = k.replace(/CTRL_H/g, 'BACKSPACE');
k = k.replace(/CTRL_I/g, 'TAB');
k = k.replace(/CTRL_M/g, 'ENTER');
return k;
});
output[i].keys = newKeys;
}
return output;
}
async start(argv) {
argv = await super.start(argv);
cliUtils.setStdout((object) => {
cliUtils.setStdout(object => {
return this.stdout(object);
});
@@ -385,6 +396,8 @@ class Application extends BaseApplication {
this.currentFolder_ = await Folder.load(Setting.value('activeFolderId'));
await this.applySettingsSideEffects();
try {
await this.execCommand(argv);
} catch (error) {
@@ -398,10 +411,11 @@ class Application extends BaseApplication {
await Setting.saveAll();
// Need to call exit() explicitely, otherwise Node wait for any timeout to complete
// Need to call exit() explicitly, otherwise Node wait for any timeout to complete
// https://stackoverflow.com/questions/18050095
process.exit(0);
} else { // Otherwise open the GUI
} else {
// Otherwise open the GUI
this.initRedux();
const keymap = await this.loadKeymaps();
@@ -421,7 +435,7 @@ class Application extends BaseApplication {
const tags = await Tag.allWithNotes();
ResourceService.runInBackground();
RevisionService.instance().runInBackground();
this.dispatch({
@@ -435,7 +449,6 @@ class Application extends BaseApplication {
});
}
}
}
let application_ = null;
@@ -446,4 +459,4 @@ function app() {
return application_;
}
module.exports = { app };
module.exports = { app };

View File

@@ -10,42 +10,47 @@ async function handleAutocompletionPromise(line) {
// Auto-complete the command name
const names = await app().commandNames();
let words = getArguments(line);
//If there is only one word and it is not already a command name then you
//should look for commmands it could be
// If there is only one word and it is not already a command name then you
// should look for commands it could be
if (words.length == 1) {
if (names.indexOf(words[0]) === -1) {
let x = names.filter((n) => n.indexOf(words[0]) === 0);
let x = names.filter(n => n.indexOf(words[0]) === 0);
if (x.length === 1) {
return x[0] + ' ';
return `${x[0]} `;
}
return x.length > 0 ? x.map((a) => a + ' ') : line;
return x.length > 0 ? x.map(a => `${a} `) : line;
} else {
return line;
}
}
//There is more than one word and it is a command
// There is more than one word and it is a command
const metadata = (await app().commandMetadata())[words[0]];
//If for some reason this command does not have any associated metadata
//just don't autocomplete. However, this should not happen.
// If for some reason this command does not have any associated metadata
// just don't autocomplete. However, this should not happen.
if (metadata === undefined) {
return line;
}
//complete an option
if (words[0] === 'tag' && words[1] === 'notetags') {
metadata.usage = 'tag <tag-command> <note>';
}
// complete an option
let next = words.length > 1 ? words[words.length - 1] : '';
let l = [];
if (next[0] === '-') {
for (let i = 0; i<metadata.options.length; i++) {
for (let i = 0; i < metadata.options.length; i++) {
const options = metadata.options[i][0].split(' ');
//if there are multiple options then they will be separated by comma and
//space. The comma should be removed
// if there are multiple options then they will be separated by comma and
// space. The comma should be removed
if (options[0][options[0].length - 1] === ',') {
options[0] = options[0].slice(0, -1);
}
if (words.includes(options[0]) || words.includes(options[1])) {
continue;
}
//First two elements are the flag and the third is the description
//Only autocomplete long
// First two elements are the flag and the third is the description
// Only autocomplete long
if (options.length > 1 && options[1].indexOf(next) === 0) {
l.push(options[1]);
} else if (options[0].indexOf(next) === 0) {
@@ -55,44 +60,43 @@ async function handleAutocompletionPromise(line) {
if (l.length === 0) {
return line;
}
let ret = l.map(a=>toCommandLine(a));
ret.prefix = toCommandLine(words.slice(0, -1)) + ' ';
let ret = l.map(a => toCommandLine(a));
ret.prefix = `${toCommandLine(words.slice(0, -1))} `;
return ret;
}
//Complete an argument
//Determine the number of positional arguments by counting the number of
//words that don't start with a - less one for the command name
const positionalArgs = words.filter((a)=>a.indexOf('-') !== 0).length - 1;
// Complete an argument
// Determine the number of positional arguments by counting the number of
// words that don't start with a - less one for the command name
const positionalArgs = words.filter(a => a.indexOf('-') !== 0).length - 1;
let cmdUsage = yargParser(metadata.usage)['_'];
cmdUsage.splice(0, 1);
if (cmdUsage.length >= positionalArgs) {
let argName = cmdUsage[positionalArgs - 1];
argName = cliUtils.parseCommandArg(argName).name;
const currentFolder = app().currentFolder();
if (argName == 'note' || argName == 'note-pattern') {
const notes = currentFolder ? await Note.previews(currentFolder.id, { titlePattern: next + '*' }) : [];
l.push(...notes.map((n) => n.title));
const notes = currentFolder ? await Note.previews(currentFolder.id, { titlePattern: `${next}*` }) : [];
l.push(...notes.map(n => n.title));
}
if (argName == 'notebook') {
const folders = await Folder.search({ titlePattern: next + '*' });
l.push(...folders.map((n) => n.title));
const folders = await Folder.search({ titlePattern: `${next}*` });
l.push(...folders.map(n => n.title));
}
if (argName == 'item') {
const notes = currentFolder ? await Note.previews(currentFolder.id, { titlePattern: next + '*' }) : [];
const folders = await Folder.search({ titlePattern: next + '*' });
l.push(...notes.map((n) => n.title), folders.map((n) => n.title));
const notes = currentFolder ? await Note.previews(currentFolder.id, { titlePattern: `${next}*` }) : [];
const folders = await Folder.search({ titlePattern: `${next}*` });
l.push(...notes.map(n => n.title), folders.map(n => n.title));
}
if (argName == 'tag') {
let tags = await Tag.search({ titlePattern: next + '*' });
l.push(...tags.map((n) => n.title));
let tags = await Tag.search({ titlePattern: `${next}*` });
l.push(...tags.map(n => n.title));
}
if (argName == 'file') {
@@ -101,7 +105,7 @@ async function handleAutocompletionPromise(line) {
}
if (argName == 'tag-command') {
let c = filterList(['add', 'remove', 'list'], next);
let c = filterList(['add', 'remove', 'list', 'notetags'], next);
l.push(...c);
}
@@ -113,12 +117,11 @@ async function handleAutocompletionPromise(line) {
if (l.length === 1) {
return toCommandLine([...words.slice(0, -1), l[0]]);
} else if (l.length > 1) {
let ret = l.map(a=>toCommandLine(a));
ret.prefix = toCommandLine(words.slice(0, -1)) + ' ';
let ret = l.map(a => toCommandLine(a));
ret.prefix = `${toCommandLine(words.slice(0, -1))} `;
return ret;
}
return line;
}
function handleAutocompletion(str, callback) {
handleAutocompletionPromise(str).then(function(res) {
@@ -127,22 +130,24 @@ function handleAutocompletion(str, callback) {
}
function toCommandLine(args) {
if (Array.isArray(args)) {
return args.map(function(a) {
if(a.indexOf('"') !== -1 || a.indexOf(' ') !== -1) {
return "'" + a + "'";
} else if (a.indexOf("'") !== -1) {
return '"' + a + '"';
} else {
return a;
}
}).join(' ');
return args
.map(function(a) {
if (a.indexOf('"') !== -1 || a.indexOf(' ') !== -1) {
return `'${a}'`;
} else if (a.indexOf('\'') !== -1) {
return `"${a}"`;
} else {
return a;
}
})
.join(' ');
} else {
if(args.indexOf('"') !== -1 || args.indexOf(' ') !== -1) {
return "'" + args + "' ";
} else if (args.indexOf("'") !== -1) {
return '"' + args + '" ';
if (args.indexOf('"') !== -1 || args.indexOf(' ') !== -1) {
return `'${args}' `;
} else if (args.indexOf('\'') !== -1) {
return `"${args}" `;
} else {
return args + ' ';
return `${args} `;
}
}
}
@@ -151,27 +156,26 @@ function getArguments(line) {
let inDoubleQuotes = false;
let currentWord = '';
let parsed = [];
for(let i = 0; i<line.length; i++) {
if(line[i] === '"') {
if(inDoubleQuotes) {
for (let i = 0; i < line.length; i++) {
if (line[i] === '"') {
if (inDoubleQuotes) {
inDoubleQuotes = false;
//maybe push word to parsed?
//currentWord += '"';
// maybe push word to parsed?
// currentWord += '"';
} else {
inDoubleQuotes = true;
//currentWord += '"';
// currentWord += '"';
}
} else if(line[i] === "'") {
if(inSingleQuotes) {
} else if (line[i] === '\'') {
if (inSingleQuotes) {
inSingleQuotes = false;
//maybe push word to parsed?
//currentWord += "'";
// maybe push word to parsed?
// currentWord += "'";
} else {
inSingleQuotes = true;
//currentWord += "'";
// currentWord += "'";
}
} else if (/\s/.test(line[i]) &&
!(inDoubleQuotes || inSingleQuotes)) {
} else if (/\s/.test(line[i]) && !(inDoubleQuotes || inSingleQuotes)) {
if (currentWord !== '') {
parsed.push(currentWord);
currentWord = '';

View File

@@ -2,7 +2,6 @@ const { _ } = require('lib/locale.js');
const { reg } = require('lib/registry.js');
class BaseCommand {
constructor() {
this.stdout_ = null;
this.prompt_ = null;
@@ -20,7 +19,7 @@ class BaseCommand {
throw new Error('Description not defined');
}
async action(args) {
async action() {
throw new Error('Action not defined');
}
@@ -93,7 +92,6 @@ class BaseCommand {
logger() {
return reg.logger();
}
}
module.exports = { BaseCommand };
module.exports = { BaseCommand };

View File

@@ -1,7 +1,7 @@
const fs = require('fs-extra');
const { fileExtension, basename, dirname } = require('lib/path-utils.js');
const { fileExtension, dirname } = require('lib/path-utils.js');
const wrap_ = require('word-wrap');
const { _, setLocale, languageCode } = require('lib/locale.js');
const { languageCode } = require('lib/locale.js');
const rootDir = dirname(dirname(__dirname));
const MAX_WIDTH = 78;
@@ -22,14 +22,14 @@ function renderOptions(options) {
let option = options[i];
const flag = option[0];
const indent = INDENT + INDENT + ' '.repeat(optionColWidth + 2);
let r = wrap(option[1], indent);
r = r.substr(flag.length + (INDENT + INDENT).length);
r = INDENT + INDENT + flag + r;
output.push(r);
}
return output.join("\n");
return output.join('\n');
}
function renderCommand(cmd) {
@@ -44,17 +44,17 @@ function renderCommand(cmd) {
output.push('');
output.push(optionString);
}
return output.join("\n");
return output.join('\n');
}
function getCommands() {
let output = [];
fs.readdirSync(__dirname).forEach((path) => {
fs.readdirSync(__dirname).forEach(path => {
if (path.indexOf('command-') !== 0) return;
const ext = fileExtension(path)
const ext = fileExtension(path);
if (ext != 'js') return;
let CommandClass = require('./' + path);
let CommandClass = require(`./${path}`);
let cmd = new CommandClass();
if (!cmd.enabled()) return;
if (cmd.hidden()) return;
@@ -87,14 +87,14 @@ function getHeader() {
let description = [];
description.push('Joplin is a note taking and to-do application, which can handle a large number of notes organised into notebooks.');
description.push('The notes are searchable, can be copied, tagged and modified with your own text editor.');
description.push("\n\n");
description.push('\n\n');
description.push('The notes can be synchronised with various target including the file system (for example with a network directory) or with Microsoft OneDrive.');
description.push("\n\n");
description.push('\n\n');
description.push('Notes exported from Evenotes via .enex files can be imported into Joplin, including the formatted content, resources (images, attachments, etc.) and complete metadata (geolocation, updated time, created time, etc.).');
output.push(wrap(description.join(''), INDENT));
return output.join("\n");
return output.join('\n');
}
function getFooter() {
@@ -102,18 +102,18 @@ function getFooter() {
output.push('WEBSITE');
output.push('');
output.push(INDENT + 'https://joplinapp.org');
output.push(`${INDENT}https://joplinapp.org`);
output.push('');
output.push('LICENSE');
output.push('');
let filePath = rootDir + '/LICENSE_' + languageCode();
if (!fs.existsSync(filePath)) filePath = rootDir + '/LICENSE';
let filePath = `${rootDir}/LICENSE_${languageCode()}`;
if (!fs.existsSync(filePath)) filePath = `${rootDir}/LICENSE`;
const licenseText = fs.readFileSync(filePath, 'utf8');
output.push(wrap(licenseText, INDENT));
return output.join("\n");
return output.join('\n');
}
async function main() {
@@ -128,12 +128,12 @@ async function main() {
}
const headerText = getHeader();
const commandsText = commandBlocks.join("\n\n");
const commandsText = commandBlocks.join('\n\n');
const footerText = getFooter();
console.info(headerText + "\n\n" + 'USAGE' + "\n\n" + commandsText + "\n\n" + footerText);
console.info(`${headerText}\n\n` + 'USAGE' + `\n\n${commandsText}\n\n${footerText}`);
}
main().catch((error) => {
main().catch(error => {
console.error(error);
});
});

View File

@@ -1,4 +1,4 @@
"use strict"
'use strict';
const fs = require('fs-extra');
const { Logger } = require('lib/logger.js');
@@ -10,14 +10,14 @@ const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Setting = require('lib/models/Setting.js');
const { sprintf } = require('sprintf-js');
const exec = require('child_process').exec
const exec = require('child_process').exec;
process.on('unhandledRejection', (reason, p) => {
console.error('Unhandled promise rejection', p, 'reason:', reason);
});
const baseDir = dirname(__dirname) + '/tests/cli-integration';
const joplinAppPath = __dirname + '/main.js';
const baseDir = `${dirname(__dirname)}/tests/cli-integration`;
const joplinAppPath = `${__dirname}/main.js`;
const logger = new Logger();
logger.addTarget('console');
@@ -32,17 +32,17 @@ db.setLogger(dbLogger);
function createClient(id) {
return {
'id': id,
'profileDir': baseDir + '/client' + id,
id: id,
profileDir: `${baseDir}/client${id}`,
};
}
const client = createClient(1);
function execCommand(client, command, options = {}) {
let exePath = 'node ' + joplinAppPath;
let cmd = exePath + ' --update-geolocation-disabled --env dev --profile ' + client.profileDir + ' ' + command;
logger.info(client.id + ': ' + command);
function execCommand(client, command) {
let exePath = `node ${joplinAppPath}`;
let cmd = `${exePath} --update-geolocation-disabled --env dev --profile ${client.profileDir} ${command}`;
logger.info(`${client.id}: ${command}`);
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
@@ -72,14 +72,7 @@ function assertEquals(expected, real) {
}
async function clearDatabase() {
await db.transactionExecBatch([
'DELETE FROM folders',
'DELETE FROM notes',
'DELETE FROM tags',
'DELETE FROM note_tags',
'DELETE FROM resources',
'DELETE FROM deleted_items',
]);
await db.transactionExecBatch(['DELETE FROM folders', 'DELETE FROM notes', 'DELETE FROM tags', 'DELETE FROM note_tags', 'DELETE FROM resources', 'DELETE FROM deleted_items']);
}
const testUnits = {};
@@ -101,7 +94,7 @@ testUnits.testFolders = async () => {
folders = await Folder.all();
assertEquals(0, folders.length);
}
};
testUnits.testNotes = async () => {
await execCommand(client, 'mkbook nb1');
@@ -121,16 +114,16 @@ testUnits.testNotes = async () => {
notes = await Note.all();
assertEquals(2, notes.length);
await execCommand(client, "rm -f 'blabla*'");
await execCommand(client, 'rm -f \'blabla*\'');
notes = await Note.all();
assertEquals(2, notes.length);
await execCommand(client, "rm -f 'n*'");
await execCommand(client, 'rm -f \'n*\'');
notes = await Note.all();
assertEquals(0, notes.length);
}
};
testUnits.testCat = async () => {
await execCommand(client, 'mkbook nb1');
@@ -145,7 +138,7 @@ testUnits.testCat = async () => {
r = await execCommand(client, 'cat -v mynote');
assertTrue(r.indexOf(note.id) >= 0);
}
};
testUnits.testConfig = async () => {
await execCommand(client, 'config editor vim');
@@ -159,7 +152,7 @@ testUnits.testConfig = async () => {
let r = await execCommand(client, 'config');
assertTrue(r.indexOf('editor') >= 0);
assertTrue(r.indexOf('subl') >= 0);
}
};
testUnits.testCp = async () => {
await execCommand(client, 'mkbook nb2');
@@ -180,7 +173,7 @@ testUnits.testCp = async () => {
notes = await Note.previews(f2.id);
assertEquals(1, notes.length);
assertEquals(notesF1[0].title, notes[0].title);
}
};
testUnits.testLs = async () => {
await execCommand(client, 'mkbook nb1');
@@ -190,7 +183,7 @@ testUnits.testLs = async () => {
assertTrue(r.indexOf('note1') >= 0);
assertTrue(r.indexOf('note2') >= 0);
}
};
testUnits.testMv = async () => {
await execCommand(client, 'mkbook nb2');
@@ -210,21 +203,21 @@ testUnits.testMv = async () => {
await execCommand(client, 'mknote note2');
await execCommand(client, 'mknote note3');
await execCommand(client, 'mknote blabla');
await execCommand(client, "mv 'note*' nb2");
await execCommand(client, 'mv \'note*\' nb2');
notes1 = await Note.previews(f1.id);
notes2 = await Note.previews(f2.id);
assertEquals(1, notes1.length);
assertEquals(4, notes2.length);
}
};
async function main(argv) {
async function main() {
await fs.remove(baseDir);
logger.info(await execCommand(client, 'version'));
await db.open({ name: client.profileDir + '/database.sqlite' });
await db.open({ name: `${client.profileDir}/database.sqlite` });
BaseModel.db_ = db;
await Setting.load();
@@ -237,13 +230,13 @@ async function main(argv) {
await clearDatabase();
let testName = n.substr(4).toLowerCase();
process.stdout.write(testName + ': ');
process.stdout.write(`${testName}: `);
await testUnits[n]();
console.info('');
}
}
main(process.argv).catch((error) => {
main(process.argv).catch(error => {
console.info('');
logger.error(error);
});
});

View File

@@ -5,7 +5,7 @@ const stringPadding = require('string-padding');
const cliUtils = {};
cliUtils.printArray = function(logFunction, rows, headers = null) {
cliUtils.printArray = function(logFunction, rows) {
if (!rows.length) return '';
const ALIGN_LEFT = 0;
@@ -16,7 +16,7 @@ cliUtils.printArray = function(logFunction, rows, headers = null) {
for (let i = 0; i < rows.length; i++) {
let row = rows[i];
for (let j = 0; j < row.length; j++) {
let item = row[j];
let width = item ? item.toString().length : 0;
@@ -26,7 +26,6 @@ cliUtils.printArray = function(logFunction, rows, headers = null) {
}
}
let lines = [];
for (let row = 0; row < rows.length; row++) {
let line = [];
for (let col = 0; col < colWidths.length; col++) {
@@ -37,7 +36,7 @@ cliUtils.printArray = function(logFunction, rows, headers = null) {
}
logFunction(line.join(' '));
}
}
};
cliUtils.parseFlags = function(flags) {
let output = {};
@@ -56,10 +55,10 @@ cliUtils.parseFlags = function(flags) {
}
}
return output;
}
};
cliUtils.parseCommandArg = function(arg) {
if (arg.length <= 2) throw new Error('Invalid command arg: ' + arg);
if (arg.length <= 2) throw new Error(`Invalid command arg: ${arg}`);
const c1 = arg[0];
const c2 = arg[arg.length - 1];
@@ -70,9 +69,9 @@ cliUtils.parseCommandArg = function(arg) {
} else if (c1 == '[' && c2 == ']') {
return { required: false, name: name };
} else {
throw new Error('Invalid command arg: ' + arg);
throw new Error(`Invalid command arg: ${arg}`);
}
}
};
cliUtils.makeCommandArgs = function(cmd, argv) {
let cmdUsage = cmd.usage();
@@ -83,9 +82,8 @@ cliUtils.makeCommandArgs = function(cmd, argv) {
let booleanFlags = [];
let aliases = {};
for (let i = 0; i < options.length; i++) {
if (options[i].length != 2) throw new Error('Invalid options: ' + options[i]);
if (options[i].length != 2) throw new Error(`Invalid options: ${options[i]}`);
let flags = options[i][0];
let text = options[i][1];
flags = cliUtils.parseFlags(flags);
@@ -125,27 +123,27 @@ cliUtils.makeCommandArgs = function(cmd, argv) {
output.options = argOptions;
return output;
}
};
cliUtils.promptMcq = function(message, answers) {
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
output: process.stdout,
});
message += "\n\n";
message += '\n\n';
for (let n in answers) {
if (!answers.hasOwnProperty(n)) continue;
message += _('%s: %s', n, answers[n]) + "\n";
message += `${_('%s: %s', n, answers[n])}\n`;
}
message += "\n";
message += '\n';
message += _('Your choice: ');
return new Promise((resolve, reject) => {
rl.question(message, (answer) => {
rl.question(message, answer => {
rl.close();
if (!(answer in answers)) {
@@ -156,7 +154,7 @@ cliUtils.promptMcq = function(message, answers) {
resolve(answer);
});
});
}
};
cliUtils.promptConfirm = function(message, answers = null) {
if (!answers) answers = [_('Y'), _('n')];
@@ -164,23 +162,24 @@ cliUtils.promptConfirm = function(message, answers = null) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
output: process.stdout,
});
message += ' (' + answers.join('/') + ')';
message += ` (${answers.join('/')})`;
return new Promise((resolve, reject) => {
rl.question(message + ' ', (answer) => {
return new Promise((resolve) => {
rl.question(`${message} `, answer => {
const ok = !answer || answer.toLowerCase() == answers[0].toLowerCase();
rl.close();
resolve(ok);
});
});
}
};
// Note: initialText is there to have the same signature as statusBar.prompt() so that
// it can be a drop-in replacement, however initialText is not used (and cannot be
// with readline.question?).
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
cliUtils.prompt = function(initialText = '', promptString = ':', options = null) {
if (!options) options = {};
@@ -189,10 +188,9 @@ cliUtils.prompt = function(initialText = '', promptString = ':', options = null)
const mutableStdout = new Writable({
write: function(chunk, encoding, callback) {
if (!this.muted)
process.stdout.write(chunk, encoding);
if (!this.muted) process.stdout.write(chunk, encoding);
callback();
}
},
});
const rl = readline.createInterface({
@@ -201,18 +199,18 @@ cliUtils.prompt = function(initialText = '', promptString = ':', options = null)
terminal: true,
});
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
mutableStdout.muted = false;
rl.question(promptString, (answer) => {
rl.question(promptString, answer => {
rl.close();
if (!!options.secure) this.stdout_('');
if (options.secure) this.stdout_('');
resolve(answer);
});
mutableStdout.muted = !!options.secure;
});
}
};
let redrawStarted_ = false;
let redrawLastLog_ = null;
@@ -220,7 +218,7 @@ let redrawLastUpdateTime_ = 0;
cliUtils.setStdout = function(v) {
this.stdout_ = v;
}
};
cliUtils.redraw = function(s) {
const now = time.unixMs();
@@ -233,8 +231,8 @@ cliUtils.redraw = function(s) {
redrawLastLog_ = s;
}
redrawStarted_ = true;
}
redrawStarted_ = true;
};
cliUtils.redrawDone = function() {
if (!redrawStarted_) return;
@@ -245,6 +243,6 @@ cliUtils.redrawDone = function() {
redrawLastLog_ = null;
redrawStarted_ = false;
}
};
module.exports = { cliUtils };
module.exports = { cliUtils };

View File

@@ -1,19 +1,12 @@
const { BaseCommand } = require('./base-command.js');
const { _ } = require('lib/locale.js');
const { cliUtils } = require('./cli-utils.js');
const EncryptionService = require('lib/services/EncryptionService');
const DecryptionWorker = require('lib/services/DecryptionWorker');
const MasterKey = require('lib/models/MasterKey');
const BaseItem = require('lib/models/BaseItem');
const BaseModel = require('lib/BaseModel');
const Setting = require('lib/models/Setting.js');
const { toTitleCase } = require('lib/string-utils.js');
const { reg } = require('lib/registry.js');
const markdownUtils = require('lib/markdownUtils');
const { Database } = require('lib/database.js');
class Command extends BaseCommand {
usage() {
return 'apidoc';
}
@@ -23,18 +16,22 @@ class Command extends BaseCommand {
}
createPropertiesTable(tableFields) {
const headers = [
{ name: 'name', label: 'Name' },
{ name: 'type', label: 'Type', filter: (value) => {
return Database.enumName('fieldType', value);
}},
{ name: 'description', label: 'Description' },
];
return markdownUtils.createMarkdownTable(headers, tableFields);
const headers = [
{ name: 'name', label: 'Name' },
{
name: 'type',
label: 'Type',
filter: value => {
return Database.enumName('fieldType', value);
},
},
{ name: 'description', label: 'Description' },
];
return markdownUtils.createMarkdownTable(headers, tableFields);
}
async action(args) {
async action() {
const models = [
{
type: BaseModel.TYPE_NOTE,
@@ -70,8 +67,8 @@ class Command extends BaseCommand {
lines.push('}');
lines.push('```');
lines.push('');
lines.push('# Authorisation')
lines.push('# Authorisation');
lines.push('');
lines.push('To prevent unauthorised applications from accessing the API, the calls must be authentified. To do so, you must provide a token as a query parameter for each API call. You can get this token from the Joplin desktop application, on the Web Clipper Options screen.');
lines.push('');
@@ -171,7 +168,7 @@ class Command extends BaseCommand {
// });
}
lines.push('# ' + toTitleCase(tableName));
lines.push(`# ${toTitleCase(tableName)}`);
lines.push('');
if (model.type === BaseModel.TYPE_FOLDER) {
@@ -184,9 +181,9 @@ class Command extends BaseCommand {
lines.push(this.createPropertiesTable(tableFields));
lines.push('');
lines.push('## GET /' + tableName);
lines.push(`## GET /${tableName}`);
lines.push('');
lines.push('Gets all ' + tableName);
lines.push(`Gets all ${tableName}`);
lines.push('');
if (model.type === BaseModel.TYPE_FOLDER) {
@@ -194,9 +191,9 @@ class Command extends BaseCommand {
lines.push('');
}
lines.push('## GET /' + tableName + '/:id');
lines.push(`## GET /${tableName}/:id`);
lines.push('');
lines.push('Gets ' + singular + ' with ID :id');
lines.push(`Gets ${singular} with ID :id`);
lines.push('');
if (model.type === BaseModel.TYPE_TAG) {
@@ -211,6 +208,11 @@ class Command extends BaseCommand {
lines.push('');
lines.push('Gets all the tags attached to this note.');
lines.push('');
lines.push('## GET /notes/:id/resources');
lines.push('');
lines.push('Gets all the resources attached to this note.');
lines.push('');
}
if (model.type === BaseModel.TYPE_FOLDER) {
@@ -227,9 +229,9 @@ class Command extends BaseCommand {
lines.push('');
}
lines.push('## POST /' + tableName);
lines.push(`## POST /${tableName}`);
lines.push('');
lines.push('Creates a new ' + singular);
lines.push(`Creates a new ${singular}`);
lines.push('');
if (model.type === BaseModel.TYPE_RESOURCE) {
@@ -273,14 +275,14 @@ class Command extends BaseCommand {
lines.push('');
}
lines.push('## PUT /' + tableName + '/:id');
lines.push(`## PUT /${tableName}/:id`);
lines.push('');
lines.push('Sets the properties of the ' + singular + ' with ID :id');
lines.push(`Sets the properties of the ${singular} with ID :id`);
lines.push('');
lines.push('## DELETE /' + tableName + '/:id');
lines.push(`## DELETE /${tableName}/:id`);
lines.push('');
lines.push('Deletes the ' + singular + ' with ID :id');
lines.push(`Deletes the ${singular} with ID :id`);
lines.push('');
if (model.type === BaseModel.TYPE_TAG) {
@@ -293,7 +295,6 @@ class Command extends BaseCommand {
this.stdout(lines.join('\n'));
}
}
module.exports = Command;

View File

@@ -3,10 +3,8 @@ const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const BaseModel = require('lib/BaseModel.js');
const { shim } = require('lib/shim.js');
const fs = require('fs-extra');
class Command extends BaseCommand {
usage() {
return 'attach <note> <file>';
}
@@ -26,7 +24,6 @@ class Command extends BaseCommand {
await shim.attachFileToNote(note, localFilePath);
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -2,11 +2,9 @@ const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
class Command extends BaseCommand {
usage() {
return 'cat <note>';
}
@@ -16,9 +14,7 @@ class Command extends BaseCommand {
}
options() {
return [
['-v, --verbose', _('Displays the complete information about note.')],
];
return [['-v, --verbose', _('Displays the complete information about note.')]];
}
async action(args) {
@@ -30,10 +26,13 @@ class Command extends BaseCommand {
const content = args.options.verbose ? await Note.serialize(item) : await Note.serializeForEdit(item);
this.stdout(content);
app().gui().showConsole();
app().gui().maximizeConsole();
app()
.gui()
.showConsole();
app()
.gui()
.maximizeConsole();
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -4,25 +4,22 @@ const { app } = require('./app.js');
const Setting = require('lib/models/Setting.js');
class Command extends BaseCommand {
usage() {
return 'config [name] [value]';
}
description() {
return _("Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.");
return _('Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.');
}
options() {
return [
['-v, --verbose', _('Also displays unset and hidden config variables.')],
];
return [['-v, --verbose', _('Also displays unset and hidden config variables.')]];
}
async action(args) {
const verbose = args.options.verbose;
const renderKeyValue = (name) => {
const renderKeyValue = name => {
const md = Setting.settingMetadata(name);
let value = Setting.value(name);
if (typeof value === 'object' || Array.isArray(value)) value = JSON.stringify(value);
@@ -33,7 +30,7 @@ class Command extends BaseCommand {
} else {
return _('%s = %s', name, value);
}
}
};
if (!args.name && !args.value) {
let keys = Setting.keys(!verbose, 'cli');
@@ -43,15 +40,23 @@ class Command extends BaseCommand {
if (!verbose && !value) continue;
this.stdout(renderKeyValue(keys[i]));
}
app().gui().showConsole();
app().gui().maximizeConsole();
app()
.gui()
.showConsole();
app()
.gui()
.maximizeConsole();
return;
}
if (args.name && !args.value) {
this.stdout(renderKeyValue(args.name));
app().gui().showConsole();
app().gui().maximizeConsole();
app()
.gui()
.showConsole();
app()
.gui()
.maximizeConsole();
return;
}
@@ -64,7 +69,6 @@ class Command extends BaseCommand {
await Setting.saveAll();
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -2,11 +2,9 @@ const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
class Command extends BaseCommand {
usage() {
return 'cp <note> [notebook]';
}
@@ -33,7 +31,6 @@ class Command extends BaseCommand {
Note.updateGeolocation(newNote.id);
}
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -2,12 +2,10 @@ const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const { time } = require('lib/time-utils.js');
class Command extends BaseCommand {
usage() {
return 'done <note>';
}
@@ -35,7 +33,6 @@ class Command extends BaseCommand {
async action(args) {
await Command.handleAction(this, args, true);
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -1,12 +1,9 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
class Command extends BaseCommand {
usage() {
return 'dump';
}
@@ -19,7 +16,7 @@ class Command extends BaseCommand {
return true;
}
async action(args) {
async action() {
let items = [];
let folders = await Folder.all();
for (let i = 0; i < folders.length; i++) {
@@ -35,10 +32,9 @@ class Command extends BaseCommand {
}
items = items.concat(tags);
this.stdout(JSON.stringify(items));
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -1,9 +1,7 @@
const { BaseCommand } = require('./base-command.js');
const { _ } = require('lib/locale.js');
const { cliUtils } = require('./cli-utils.js');
const EncryptionService = require('lib/services/EncryptionService');
const DecryptionWorker = require('lib/services/DecryptionWorker');
const MasterKey = require('lib/models/MasterKey');
const BaseItem = require('lib/models/BaseItem');
const Setting = require('lib/models/Setting.js');
const { shim } = require('lib/shim');
@@ -12,7 +10,6 @@ const imageType = require('image-type');
const readChunk = require('read-chunk');
class Command extends BaseCommand {
usage() {
return 'e2ee <command> [path]';
}
@@ -35,7 +32,7 @@ class Command extends BaseCommand {
const options = args.options;
const askForMasterKey = async (error) => {
const askForMasterKey = async error => {
const masterKeyId = error.masterKeyId;
const password = await this.prompt(_('Enter master password:'), { type: 'string', secure: true });
if (!password) {
@@ -45,7 +42,7 @@ class Command extends BaseCommand {
Setting.setObjectKey('encryption.passwordCache', masterKeyId, password);
await EncryptionService.instance().loadMasterKeysFromSettings();
return true;
}
};
if (args.command === 'enable') {
const password = options.password ? options.password.toString() : await this.prompt(_('Enter master password:'), { type: 'string', secure: true });
@@ -53,7 +50,15 @@ class Command extends BaseCommand {
this.stdout(_('Operation cancelled'));
return;
}
const password2 = await this.prompt(_('Confirm password:'), { type: 'string', secure: true });
if (!password2) {
this.stdout(_('Operation cancelled'));
return;
}
if (password !== password2) {
this.stdout(_('Passwords do not match!'));
return;
}
await EncryptionService.instance().generateMasterKeyAndEnableEncryption(password);
return;
}
@@ -100,13 +105,13 @@ class Command extends BaseCommand {
while (true) {
try {
const outputDir = options.output ? options.output : require('os').tmpdir();
let outFile = outputDir + '/' + pathUtils.filename(args.path) + '.' + Date.now() + '.bin';
let outFile = `${outputDir}/${pathUtils.filename(args.path)}.${Date.now()}.bin`;
await EncryptionService.instance().decryptFile(args.path, outFile);
const buffer = await readChunk(outFile, 0, 64);
const detectedType = imageType(buffer);
if (detectedType) {
const newOutFile = outFile + '.' + detectedType.ext;
const newOutFile = `${outFile}.${detectedType.ext}`;
await shim.fsDriver().move(outFile, newOutFile);
outFile = newOutFile;
}
@@ -128,19 +133,17 @@ class Command extends BaseCommand {
if (args.command === 'target-status') {
const fs = require('fs-extra');
const pathUtils = require('lib/path-utils.js');
const fsDriver = new (require('lib/fs-driver-node.js').FsDriverNode)();
const targetPath = args.path;
if (!targetPath) throw new Error('Please specify the sync target path.');
const dirPaths = function(targetPath) {
let paths = [];
fs.readdirSync(targetPath).forEach((path) => {
fs.readdirSync(targetPath).forEach(path => {
paths.push(path);
});
return paths;
}
};
let itemCount = 0;
let resourceCount = 0;
@@ -155,7 +158,7 @@ class Command extends BaseCommand {
for (let i = 0; i < paths.length; i++) {
const path = paths[i];
const fullPath = targetPath + '/' + path;
const fullPath = `${targetPath}/${path}`;
const stat = await fs.stat(fullPath);
// this.stdout(fullPath);
@@ -165,7 +168,7 @@ class Command extends BaseCommand {
for (let j = 0; j < resourcePaths.length; j++) {
const resourcePath = resourcePaths[j];
resourceCount++;
const fullResourcePath = fullPath + '/' + resourcePath;
const fullResourcePath = `${fullPath}/${resourcePath}`;
const isEncrypted = await EncryptionService.instance().fileIsEncrypted(fullResourcePath);
if (isEncrypted) {
encryptedResourceCount++;
@@ -199,9 +202,9 @@ class Command extends BaseCommand {
}
}
this.stdout('Encrypted items: ' + encryptedItemCount + '/' + itemCount);
this.stdout('Encrypted resources: ' + encryptedResourceCount + '/' + resourceCount);
this.stdout('Other items (never encrypted): ' + otherItemCount);
this.stdout(`Encrypted items: ${encryptedItemCount}/${itemCount}`);
this.stdout(`Encrypted resources: ${encryptedResourceCount}/${resourceCount}`);
this.stdout(`Other items (never encrypted): ${otherItemCount}`);
if (options.verbose) {
this.stdout('');
@@ -224,7 +227,6 @@ class Command extends BaseCommand {
return;
}
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -1,17 +1,14 @@
const fs = require('fs-extra');
const { BaseCommand } = require('./base-command.js');
const { splitCommandString } = require('lib/string-utils.js');
const { uuid } = require('lib/uuid.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Setting = require('lib/models/Setting.js');
const BaseModel = require('lib/BaseModel.js');
const { cliUtils } = require('./cli-utils.js');
const { time } = require('lib/time-utils.js');
class Command extends BaseCommand {
usage() {
return 'edit <note>';
}
@@ -21,20 +18,19 @@ class Command extends BaseCommand {
}
async action(args) {
let watcher = null;
let tempFilePath = null;
const onFinishedEditing = async () => {
if (tempFilePath) fs.removeSync(tempFilePath);
}
};
const textEditorPath = () => {
if (Setting.value('editor')) return Setting.value('editor');
if (process.env.EDITOR) return process.env.EDITOR;
throw new Error(_('No text editor is defined. Please set it using `config editor <editor-path>`'));
}
};
try {
try {
// -------------------------------------------------------------------------
// Load note or create it if it doesn't exist
// -------------------------------------------------------------------------
@@ -58,14 +54,14 @@ class Command extends BaseCommand {
// -------------------------------------------------------------------------
let editorPath = textEditorPath();
let editorArgs = editorPath.split(' ');
let editorArgs = splitCommandString(editorPath);
editorPath = editorArgs[0];
editorArgs = editorArgs.splice(1);
const originalContent = await Note.serializeForEdit(note);
tempFilePath = Setting.value('tempDir') + '/' + uuid.create() + '.md';
tempFilePath = `${Setting.value('tempDir')}/${uuid.create()}.md`;
editorArgs.push(tempFilePath);
await fs.writeFile(tempFilePath, originalContent);
@@ -80,7 +76,7 @@ class Command extends BaseCommand {
await app().gui().forceRender();
const termState = app().gui().termSaveState();
const spawnSync = require('child_process').spawnSync;
const spawnSync = require('child_process').spawnSync;
const result = spawnSync(editorPath, editorArgs, { stdio: 'inherit' });
if (result.error) this.stdout(_('Error opening note in editor: %s', result.error.message));
@@ -107,13 +103,11 @@ class Command extends BaseCommand {
});
await onFinishedEditing();
} catch(error) {
} catch (error) {
await onFinishedEditing();
throw error;
}
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -3,7 +3,6 @@ const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
class Command extends BaseCommand {
usage() {
return 'exit';
}
@@ -16,10 +15,9 @@ class Command extends BaseCommand {
return ['gui'];
}
async action(args) {
async action() {
await app().exit();
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -1,13 +1,10 @@
const { BaseCommand } = require('./base-command.js');
const { Database } = require('lib/database.js');
const { app } = require('./app.js');
const Setting = require('lib/models/Setting.js');
const { _ } = require('lib/locale.js');
const { ReportService } = require('lib/services/report.js');
const fs = require('fs-extra');
class Command extends BaseCommand {
usage() {
return 'export-sync-status';
}
@@ -20,17 +17,20 @@ class Command extends BaseCommand {
return true;
}
async action(args) {
async action() {
const service = new ReportService();
const csv = await service.basicItemList({ format: 'csv' });
const filePath = Setting.value('profileDir') + '/syncReport-' + (new Date()).getTime() + '.csv';
const filePath = `${Setting.value('profileDir')}/syncReport-${new Date().getTime()}.csv`;
await fs.writeFileSync(filePath, csv);
this.stdout('Sync status exported to ' + filePath);
this.stdout(`Sync status exported to ${filePath}`);
app().gui().showConsole();
app().gui().maximizeConsole();
app()
.gui()
.showConsole();
app()
.gui()
.maximizeConsole();
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -1,14 +1,10 @@
const { BaseCommand } = require('./base-command.js');
const InteropService = require('lib/services/InteropService.js');
const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js');
const { reg } = require('lib/registry.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const fs = require('fs-extra');
class Command extends BaseCommand {
usage() {
return 'export <path>';
}
@@ -19,17 +15,14 @@ class Command extends BaseCommand {
options() {
const service = new InteropService();
const formats = service.modules()
const formats = service
.modules()
.filter(m => m.type === 'exporter')
.map(m => m.format + (m.description ? ' (' + m.description + ')' : ''));
.map(m => m.format + (m.description ? ` (${m.description})` : ''));
return [
['--format <format>', _('Destination format: %s', formats.join(', '))],
['--note <note>', _('Exports only the given note.')],
['--notebook <notebook>', _('Exports only the given notebook.')],
];
return [['--format <format>', _('Destination format: %s', formats.join(', '))], ['--note <note>', _('Exports only the given note.')], ['--notebook <notebook>', _('Exports only the given notebook.')]];
}
async action(args) {
let exportOptions = {};
exportOptions.path = args.path;
@@ -37,25 +30,20 @@ class Command extends BaseCommand {
exportOptions.format = args.options.format ? args.options.format : 'jex';
if (args.options.note) {
const notes = await app().loadItems(BaseModel.TYPE_NOTE, args.options.note, { parent: app().currentFolder() });
if (!notes.length) throw new Error(_('Cannot find "%s".', args.options.note));
exportOptions.sourceNoteIds = notes.map((n) => n.id);
exportOptions.sourceNoteIds = notes.map(n => n.id);
} else if (args.options.notebook) {
const folders = await app().loadItems(BaseModel.TYPE_FOLDER, args.options.notebook);
if (!folders.length) throw new Error(_('Cannot find "%s".', args.options.notebook));
exportOptions.sourceFolderIds = folders.map((n) => n.id);
exportOptions.sourceFolderIds = folders.map(n => n.id);
}
const service = new InteropService();
const result = await service.export(exportOptions);
result.warnings.map((w) => this.stdout(w));
result.warnings.map(w => this.stdout(w));
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -2,11 +2,9 @@ const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
class Command extends BaseCommand {
usage() {
return 'geoloc <note>';
}
@@ -23,9 +21,10 @@ class Command extends BaseCommand {
const url = Note.geolocationUrl(item);
this.stdout(url);
app().gui().showConsole();
app()
.gui()
.showConsole();
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -1,14 +1,10 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { renderCommandHelp } = require('./help-utils.js');
const { Database } = require('lib/database.js');
const Setting = require('lib/models/Setting.js');
const { wrap } = require('lib/string-utils.js');
const { _ } = require('lib/locale.js');
const { cliUtils } = require('./cli-utils.js');
class Command extends BaseCommand {
usage() {
return 'help [command]';
}
@@ -28,7 +24,7 @@ class Command extends BaseCommand {
output.push(command);
}
output.sort((a, b) => a.name() < b.name() ? -1 : +1);
output.sort((a, b) => (a.name() < b.name() ? -1 : +1));
return output;
}
@@ -40,31 +36,37 @@ class Command extends BaseCommand {
this.stdout(_('For information on how to customise the shortcuts please visit %s', 'https://joplinapp.org/terminal/#shortcuts'));
this.stdout('');
if (app().gui().isDummy()) {
if (
app()
.gui()
.isDummy()
) {
throw new Error(_('Shortcuts are not available in CLI mode.'));
}
const keymap = app().gui().keymap();
const keymap = app()
.gui()
.keymap();
let rows = [];
for (let i = 0; i < keymap.length; i++) {
const item = keymap[i];
const keys = item.keys.map((k) => k === ' ' ? '(SPACE)' : k);
const keys = item.keys.map(k => (k === ' ' ? '(SPACE)' : k));
rows.push([keys.join(', '), item.command]);
}
cliUtils.printArray(this.stdout.bind(this), rows);
} else if (args.command === 'all') {
const commands = this.allCommands();
const output = commands.map((c) => renderCommandHelp(c));
const output = commands.map(c => renderCommandHelp(c));
this.stdout(output.join('\n\n'));
} else if (args.command) {
const command = app().findCommandByName(args['command']);
if (!command) throw new Error(_('Cannot find "%s".', args.command));
this.stdout(renderCommandHelp(command, stdoutWidth));
} else {
const commandNames = this.allCommands().map((a) => a.name());
const commandNames = this.allCommands().map(a => a.name());
this.stdout(_('Type `help [command]` for more information about a command; or type `help all` for the complete usage information.'));
this.stdout('');
@@ -82,10 +84,13 @@ class Command extends BaseCommand {
this.stdout(_('For the list of keyboard shortcuts and config options, type `help keymap`'));
}
app().gui().showConsole();
app().gui().maximizeConsole();
app()
.gui()
.showConsole();
app()
.gui()
.maximizeConsole();
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -1,17 +1,11 @@
const { BaseCommand } = require('./base-command.js');
const InteropService = require('lib/services/InteropService.js');
const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js');
const { filename, basename, fileExtension } = require('lib/path-utils.js');
const { importEnex } = require('lib/import-enex');
const { cliUtils } = require('./cli-utils.js');
const { reg } = require('lib/registry.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const fs = require('fs-extra');
class Command extends BaseCommand {
usage() {
return 'import <path> [notebook]';
}
@@ -22,14 +16,14 @@ class Command extends BaseCommand {
options() {
const service = new InteropService();
const formats = service.modules().filter(m => m.type === 'importer').map(m => m.format);
const formats = service
.modules()
.filter(m => m.type === 'importer')
.map(m => m.format);
return [
['--format <format>', _('Source format: %s', (['auto'].concat(formats)).join(', '))],
['-f, --force', _('Do not ask for confirmation.')],
];
return [['--format <format>', _('Source format: %s', ['auto'].concat(formats).join(', '))], ['-f, --force', _('Do not ask for confirmation.')]];
}
async action(args) {
let folder = await app().loadItem(BaseModel.TYPE_FOLDER, args.notebook);
@@ -44,7 +38,7 @@ class Command extends BaseCommand {
// onProgress/onError supported by Enex import only
importOptions.onProgress = (progressState) => {
importOptions.onProgress = progressState => {
let line = [];
line.push(_('Found: %d.', progressState.loaded));
line.push(_('Created: %d.', progressState.created));
@@ -56,20 +50,21 @@ class Command extends BaseCommand {
cliUtils.redraw(lastProgress);
};
importOptions.onError = (error) => {
importOptions.onError = error => {
let s = error.trace ? error.trace : error.toString();
this.stdout(s);
};
app().gui().showConsole();
app()
.gui()
.showConsole();
this.stdout(_('Importing notes...'));
const service = new InteropService();
const result = await service.import(importOptions);
result.warnings.map((w) => this.stdout(w));
result.warnings.map(w => this.stdout(w));
cliUtils.redrawDone();
if (lastProgress) this.stdout(_('The notes have been imported: %s', lastProgress));
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -10,7 +10,6 @@ const { time } = require('lib/time-utils.js');
const { cliUtils } = require('./cli-utils.js');
class Command extends BaseCommand {
usage() {
return 'ls [note-pattern]';
}
@@ -24,14 +23,7 @@ class Command extends BaseCommand {
}
options() {
return [
['-n, --limit <num>', _('Displays only the first top <num> notes.')],
['-s, --sort <field>', _('Sorts the item by <field> (eg. title, updated_time, created_time).')],
['-r, --reverse', _('Reverses the sorting order.')],
['-t, --type <type>', _('Displays only the items of the specific type(s). Can be `n` for notes, `t` for to-dos, or `nt` for notes and to-dos (eg. `-tt` would display only the to-dos, while `-ttd` would display notes and to-dos.')],
['-f, --format <format>', _('Either "text" or "json"')],
['-l, --long', _('Use long list format. Format is ID, NOTE_COUNT (for notebook), DATE, TODO_CHECKED (for to-dos), TITLE')],
];
return [['-n, --limit <num>', _('Displays only the first top <num> notes.')], ['-s, --sort <field>', _('Sorts the item by <field> (eg. title, updated_time, created_time).')], ['-r, --reverse', _('Reverses the sorting order.')], ['-t, --type <type>', _('Displays only the items of the specific type(s). Can be `n` for notes, `t` for to-dos, or `nt` for notes and to-dos (eg. `-tt` would display only the to-dos, while `-ttd` would display notes and to-dos.')], ['-f, --format <format>', _('Either "text" or "json"')], ['-l, --long', _('Use long list format. Format is ID, NOTE_COUNT (for notebook), DATE, TODO_CHECKED (for to-dos), TITLE')]];
}
async action(args) {
@@ -98,14 +90,14 @@ class Command extends BaseCommand {
let title = item.title;
if (!shortIdShown && (seenTitles.indexOf(item.title) >= 0 || !item.title)) {
title += ' (' + BaseModel.shortId(item.id) + ')';
title += ` (${BaseModel.shortId(item.id)})`;
} else {
seenTitles.push(item.title);
}
if (hasTodos) {
if (item.is_todo) {
row.push(sprintf('[%s]', !!item.todo_completed ? 'X' : ' '));
row.push(sprintf('[%s]', item.todo_completed ? 'X' : ' '));
} else {
row.push(' ');
}
@@ -118,9 +110,7 @@ class Command extends BaseCommand {
cliUtils.printArray(this.stdout.bind(this), rows);
}
}
}
module.exports = Command;

View File

@@ -2,10 +2,8 @@ const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const Folder = require('lib/models/Folder.js');
const { reg } = require('lib/registry.js');
class Command extends BaseCommand {
usage() {
return 'mkbook <new-notebook>';
}
@@ -15,10 +13,9 @@ class Command extends BaseCommand {
}
async action(args) {
let folder = await Folder.save({ title: args['new-notebook'] }, { userSideValidation: true });
let folder = await Folder.save({ title: args['new-notebook'] }, { userSideValidation: true });
app().switchCurrentFolder(folder);
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -4,7 +4,6 @@ const { _ } = require('lib/locale.js');
const Note = require('lib/models/Note.js');
class Command extends BaseCommand {
usage() {
return 'mknote <new-note>';
}
@@ -26,7 +25,6 @@ class Command extends BaseCommand {
app().switchCurrentFolder(app().currentFolder());
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -4,7 +4,6 @@ const { _ } = require('lib/locale.js');
const Note = require('lib/models/Note.js');
class Command extends BaseCommand {
usage() {
return 'mktodo <new-todo>';
}
@@ -27,7 +26,6 @@ class Command extends BaseCommand {
app().switchCurrentFolder(app().currentFolder());
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -6,7 +6,6 @@ const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
class Command extends BaseCommand {
usage() {
return 'mv <note> [notebook]';
}
@@ -18,7 +17,7 @@ class Command extends BaseCommand {
async action(args) {
const pattern = args['note'];
const destination = args['notebook'];
const folder = await Folder.loadByField('title', destination);
if (!folder) throw new Error(_('Cannot find "%s".', destination));
@@ -29,7 +28,6 @@ class Command extends BaseCommand {
await Note.moveToFolder(notes[i].id, folder.id);
}
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -6,7 +6,6 @@ const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
class Command extends BaseCommand {
usage() {
return 'ren <item> <name>';
}
@@ -35,7 +34,6 @@ class Command extends BaseCommand {
await Note.save(newItem);
}
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -1,14 +1,10 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const BaseItem = require('lib/models/BaseItem.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const BaseModel = require('lib/BaseModel.js');
const { cliUtils } = require('./cli-utils.js');
class Command extends BaseCommand {
usage() {
return 'rmbook <notebook>';
}
@@ -18,9 +14,7 @@ class Command extends BaseCommand {
}
options() {
return [
['-f, --force', _('Deletes the notebook without asking for confirmation.')],
];
return [['-f, --force', _('Deletes the notebook without asking for confirmation.')]];
}
async action(args) {
@@ -34,7 +28,6 @@ class Command extends BaseCommand {
await Folder.delete(folder.id);
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -1,14 +1,10 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const BaseItem = require('lib/models/BaseItem.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const BaseModel = require('lib/BaseModel.js');
const { cliUtils } = require('./cli-utils.js');
class Command extends BaseCommand {
usage() {
return 'rmnote <note-pattern>';
}
@@ -18,9 +14,7 @@ class Command extends BaseCommand {
}
options() {
return [
['-f, --force', _('Deletes the notes without asking for confirmation.')],
];
return [['-f, --force', _('Deletes the notes without asking for confirmation.')]];
}
async action(args) {
@@ -32,10 +26,9 @@ class Command extends BaseCommand {
const ok = force ? true : await this.prompt(notes.length > 1 ? _('%d notes match this pattern. Delete them?', notes.length) : _('Delete note?'), { booleanAnswerDefault: 'n' });
if (!ok) return;
let ids = notes.map((n) => n.id);
let ids = notes.map(n => n.id);
await Note.batchDelete(ids);
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -1,15 +1,10 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const { sprintf } = require('sprintf-js');
const { time } = require('lib/time-utils.js');
const { uuid } = require('lib/uuid.js');
class Command extends BaseCommand {
usage() {
return 'search <pattern> [notebook]';
}
@@ -50,7 +45,6 @@ class Command extends BaseCommand {
id: searchId,
});
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -0,0 +1,57 @@
const { BaseCommand } = require('./base-command.js');
const { _ } = require('lib/locale.js');
const Setting = require('lib/models/Setting.js');
const { Logger } = require('lib/logger.js');
const { shim } = require('lib/shim');
class Command extends BaseCommand {
usage() {
return 'server <command>';
}
description() {
return `${_('Start, stop or check the API server. To specify on which port it should run, set the api.port config variable. Commands are (%s).', ['start', 'stop', 'status'].join('|'))} This is an experimental feature - use at your own risks! It is recommended that the server runs off its own separate profile so that no two CLI instances access that profile at the same time. Use --profile to specify the profile path.`;
}
async action(args) {
const command = args.command;
const ClipperServer = require('lib/ClipperServer');
const stdoutFn = (s) => this.stdout(s);
const clipperLogger = new Logger();
clipperLogger.addTarget('file', { path: `${Setting.value('profileDir')}/log-clipper.txt` });
clipperLogger.addTarget('console', { console: {
info: stdoutFn,
warn: stdoutFn,
error: stdoutFn,
}});
ClipperServer.instance().setDispatch(() => {});
ClipperServer.instance().setLogger(clipperLogger);
const pidPath = `${Setting.value('profileDir')}/clipper-pid.txt`;
const runningOnPort = await ClipperServer.instance().isRunning();
if (command === 'start') {
if (runningOnPort) {
this.stdout(_('Server is already running on port %d', runningOnPort));
} else {
await shim.fsDriver().writeFile(pidPath, process.pid.toString(), 'utf-8');
await ClipperServer.instance().start(); // Never exit
}
} else if (command === 'status') {
this.stdout(runningOnPort ? _('Server is running on port %d', runningOnPort) : _('Server is not running.'));
} else if (command === 'stop') {
if (!runningOnPort) {
this.stdout(_('Server is not running.'));
return;
}
const pid = await shim.fsDriver().readFile(pidPath);
if (!pid) return;
process.kill(pid, 'SIGTERM');
}
}
}
module.exports = Command;

View File

@@ -3,12 +3,9 @@ const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const BaseModel = require('lib/BaseModel.js');
const { Database } = require('lib/database.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const BaseItem = require('lib/models/BaseItem.js');
class Command extends BaseCommand {
usage() {
return 'set <note> <name> [value]';
}
@@ -19,7 +16,7 @@ class Command extends BaseCommand {
for (let i = 0; i < fields.length; i++) {
const f = fields[i];
if (f.name === 'id') continue;
s.push(f.name + ' (' + Database.enumName('fieldType', f.type) + ')');
s.push(`${f.name} (${Database.enumName('fieldType', f.type)})`);
}
return _('Sets the property <name> of the given <note> to the given [value]. Possible properties are:\n\n%s', s.join(', '));
@@ -42,10 +39,16 @@ class Command extends BaseCommand {
type_: notes[i].type_,
};
newNote[propName] = propValue;
await Note.save(newNote);
const timestamp = Date.now();
await Note.save(newNote, {
autoTimestamp: false, // No auto-timestamp because user may have provided them
updated_time: timestamp,
created_time: timestamp,
});
}
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -1,12 +1,10 @@
const { BaseCommand } = require('./base-command.js');
const { Database } = require('lib/database.js');
const { app } = require('./app.js');
const Setting = require('lib/models/Setting.js');
const { _ } = require('lib/locale.js');
const { ReportService } = require('lib/services/report.js');
class Command extends BaseCommand {
usage() {
return 'status';
}
@@ -15,7 +13,7 @@ class Command extends BaseCommand {
return _('Displays summary about the notes and notebooks.');
}
async action(args) {
async action() {
let service = new ReportService();
let report = await service.status(Setting.value('sync.target'));
@@ -24,7 +22,7 @@ class Command extends BaseCommand {
if (i > 0) this.stdout('');
this.stdout('# ' + section.title);
this.stdout(`# ${section.title}`);
this.stdout('');
for (let n in section.body) {
@@ -34,10 +32,13 @@ class Command extends BaseCommand {
}
}
app().gui().showConsole();
app().gui().maximizeConsole();
app()
.gui()
.showConsole();
app()
.gui()
.maximizeConsole();
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -3,7 +3,6 @@ const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const { OneDriveApiNodeUtils } = require('./onedrive-api-node-utils.js');
const Setting = require('lib/models/Setting.js');
const BaseItem = require('lib/models/BaseItem.js');
const ResourceFetcher = require('lib/services/ResourceFetcher');
const { Synchronizer } = require('lib/synchronizer.js');
const { reg } = require('lib/registry.js');
@@ -14,7 +13,6 @@ const fs = require('fs-extra');
const SyncTargetRegistry = require('lib/SyncTargetRegistry');
class Command extends BaseCommand {
constructor() {
super();
this.syncTargetId_ = null;
@@ -31,9 +29,7 @@ class Command extends BaseCommand {
}
options() {
return [
['--target <target>', _('Sync to provided target (defaults to sync.target config value)')],
];
return [['--target <target>', _('Sync to provided target (defaults to sync.target config value)')]];
}
static lockFile(filePath) {
@@ -66,21 +62,25 @@ class Command extends BaseCommand {
const syncTarget = reg.syncTarget(this.syncTargetId_);
const syncTargetMd = SyncTargetRegistry.idToMetadata(this.syncTargetId_);
if (this.syncTargetId_ === 3 || this.syncTargetId_ === 4) { // OneDrive
if (this.syncTargetId_ === 3 || this.syncTargetId_ === 4) {
// OneDrive
this.oneDriveApiUtils_ = new OneDriveApiNodeUtils(syncTarget.api());
const auth = await this.oneDriveApiUtils_.oauthDance({
log: (...s) => { return this.stdout(...s); }
log: (...s) => {
return this.stdout(...s);
},
});
this.oneDriveApiUtils_ = null;
Setting.setValue('sync.' + this.syncTargetId_ + '.auth', auth ? JSON.stringify(auth) : null);
Setting.setValue(`sync.${this.syncTargetId_}.auth`, auth ? JSON.stringify(auth) : null);
if (!auth) {
this.stdout(_('Authentication was not completed (did not receive an authentication token).'));
return false;
}
return true;
} else if (syncTargetMd.name === 'dropbox') { // Dropbox
} else if (syncTargetMd.name === 'dropbox') {
// Dropbox
const api = await syncTarget.api();
const loginUrl = api.loginUrl();
this.stdout(_('To allow Joplin to synchronise with Dropbox, please follow the steps below:'));
@@ -93,7 +93,7 @@ class Command extends BaseCommand {
}
const response = await api.execAuthToken(authCode);
Setting.setValue('sync.' + this.syncTargetId_ + '.auth', response.access_token);
Setting.setValue(`sync.${this.syncTargetId_}.auth`, response.access_token);
api.setAuthToken(response.access_token);
return true;
}
@@ -117,8 +117,8 @@ class Command extends BaseCommand {
this.releaseLockFn_ = null;
// Lock is unique per profile/database
const lockFilePath = require('os').tmpdir() + '/synclock_' + md5(escape(Setting.value('profileDir'))); // https://github.com/pvorb/node-md5/issues/41
if (!await fs.pathExists(lockFilePath)) await fs.writeFile(lockFilePath, 'synclock');
const lockFilePath = `${require('os').tmpdir()}/synclock_${md5(escape(Setting.value('profileDir')))}`; // https://github.com/pvorb/node-md5/issues/41
if (!(await fs.pathExists(lockFilePath))) await fs.writeFile(lockFilePath, 'synclock');
try {
if (await Command.isLocked(lockFilePath)) throw new Error(_('Synchronisation is already in progress.'));
@@ -147,22 +147,26 @@ class Command extends BaseCommand {
const syncTarget = reg.syncTarget(this.syncTargetId_);
if (!await syncTarget.isAuthenticated()) {
app().gui().showConsole();
app().gui().maximizeConsole();
if (!(await syncTarget.isAuthenticated())) {
app()
.gui()
.showConsole();
app()
.gui()
.maximizeConsole();
const authDone = await this.doAuth();
if (!authDone) return cleanUp();
}
const sync = await syncTarget.synchronizer();
let options = {
onProgress: (report) => {
onProgress: report => {
let lines = Synchronizer.reportToLines(report);
if (lines.length) cliUtils.redraw(lines.join(' '));
},
onMessage: (msg) => {
onMessage: msg => {
cliUtils.redrawDone();
this.stdout(msg);
},
@@ -174,7 +178,7 @@ class Command extends BaseCommand {
this.stdout(_('Starting synchronisation...'));
const contextKey = 'sync.' + this.syncTargetId_ + '.context';
const contextKey = `sync.${this.syncTargetId_}.context`;
let context = Setting.value(contextKey);
context = context ? JSON.parse(context) : {};
@@ -193,7 +197,7 @@ class Command extends BaseCommand {
// When using the tool in command line mode, the ResourceFetcher service is
// not going to be running in the background, so the resources need to be
// explicitely downloaded below.
// explicitly downloaded below.
if (!app().hasGui()) {
this.stdout(_('Downloading resources...'));
await ResourceFetcher.instance().fetchAll();
@@ -237,7 +241,6 @@ class Command extends BaseCommand {
cancellable() {
return true;
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -6,19 +6,16 @@ const BaseModel = require('lib/BaseModel.js');
const { time } = require('lib/time-utils.js');
class Command extends BaseCommand {
usage() {
return 'tag <tag-command> [tag] [note]';
}
description() {
return _('<tag-command> can be "add", "remove" or "list" to assign or remove [tag] from [note], or to list the notes associated with [tag]. The command `tag list` can be used to list all the tags (use -l for long option).');
return _('<tag-command> can be "add", "remove", "list", or "notetags" to assign or remove [tag] from [note], to list notes associated with [tag], or to list tags associated with [note]. The command `tag list` can be used to list all the tags (use -l for long option).');
}
options() {
return [
['-l, --long', _('Use long list format. Format is ID, NOTE_COUNT (for notebook), DATE, TODO_CHECKED (for to-dos), TITLE')],
];
return [['-l, --long', _('Use long list format. Format is ID, NOTE_COUNT (for notebook), DATE, TODO_CHECKED (for to-dos), TITLE')]];
}
async action(args) {
@@ -50,7 +47,7 @@ class Command extends BaseCommand {
} else if (command == 'list') {
if (tag) {
let notes = await Tag.notes(tag.id);
notes.map((note) => {
notes.map(note => {
let line = '';
if (options.long) {
line += BaseModel.shortId(note.id);
@@ -61,7 +58,7 @@ class Command extends BaseCommand {
if (note.is_todo) {
line += '[';
if (note.todo_completed) {
line += 'X';
line += 'X';
} else {
line += ' ';
}
@@ -74,13 +71,25 @@ class Command extends BaseCommand {
});
} else {
let tags = await Tag.all();
tags.map((tag) => { this.stdout(tag.title); });
tags.map(tag => {
this.stdout(tag.title);
});
}
} else if (command == 'notetags') {
if (args.tag) {
const note = await app().loadItem(BaseModel.TYPE_NOTE, args.tag);
if (!note) throw new Error(_('Cannot find "%s".', args.tag));
const tags = await Tag.tagsByNoteId(note.id);
tags.map(tag => {
this.stdout(tag.title);
});
} else {
throw new Error(_('Cannot find "%s".', ''));
}
} else {
throw new Error(_('Invalid command: "%s"', command));
}
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -2,12 +2,10 @@ const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const { time } = require('lib/time-utils.js');
class Command extends BaseCommand {
usage() {
return 'todo <todo-command> <note-pattern>';
}
@@ -39,12 +37,11 @@ class Command extends BaseCommand {
}
} else if (action == 'clear') {
toSave.is_todo = 0;
}
}
await Note.save(toSave);
}
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -1,15 +1,9 @@
const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const { time } = require('lib/time-utils.js');
const CommandDone = require('./command-done.js');
class Command extends BaseCommand {
usage() {
return 'undone <note>';
}
@@ -21,7 +15,6 @@ class Command extends BaseCommand {
async action(args) {
await CommandDone.handleAction(this, args, false);
}
}
module.exports = Command;
module.exports = Command;

View File

@@ -2,10 +2,8 @@ const { BaseCommand } = require('./base-command.js');
const { app } = require('./app.js');
const { _ } = require('lib/locale.js');
const BaseModel = require('lib/BaseModel.js');
const Folder = require('lib/models/Folder.js');
class Command extends BaseCommand {
usage() {
return 'use <notebook>';
}
@@ -14,10 +12,6 @@ class Command extends BaseCommand {
return _('Switches to [notebook] - all further operations will happen within this notebook.');
}
autocomplete() {
return { data: autocompleteFolders };
}
compatibleUis() {
return ['cli'];
}
@@ -27,7 +21,6 @@ class Command extends BaseCommand {
if (!folder) throw new Error(_('Cannot find "%s".', args['notebook']));
app().switchCurrentFolder(folder);
}
}
module.exports = Command;
module.exports = Command;

Some files were not shown because too many files have changed in this diff Show More