diff --git a/.eslintignore b/.eslintignore
index 77b8d0ac4..f068e85e8 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -230,6 +230,7 @@ packages/app-desktop/gui/MainScreen/commands/showNoteProperties.js
packages/app-desktop/gui/MainScreen/commands/showPrompt.js
packages/app-desktop/gui/MainScreen/commands/showShareFolderDialog.js
packages/app-desktop/gui/MainScreen/commands/showShareNoteDialog.js
+packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.test.js
packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.js
packages/app-desktop/gui/MainScreen/commands/toggleEditors.js
packages/app-desktop/gui/MainScreen/commands/toggleLayoutMoveMode.js
diff --git a/.github/scripts/run_ci.sh b/.github/scripts/run_ci.sh
index cdeca0421..6db4364ad 100755
--- a/.github/scripts/run_ci.sh
+++ b/.github/scripts/run_ci.sh
@@ -207,6 +207,22 @@ if [ "$RUN_TESTS" == "1" ]; then
fi
fi
+# =============================================================================
+# Spellchecking
+# =============================================================================
+
+if [ "$IS_PULL_REQUEST" == "1" ]; then
+ if [ "$IS_LINUX" == "1" ]; then
+ echo "Step: Spellchecking..."
+
+ yarn spellcheck --all
+ testResult=$?
+ if [ $testResult -ne 0 ]; then
+ exit $testResult
+ fi
+ fi
+fi
+
# =============================================================================
# Find out if we should run the build or not. Electron-builder gets stuck when
# building PRs so we disable it in this case. The Linux build should provide
diff --git a/.gitignore b/.gitignore
index 3a4304426..e8edeb8f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -210,6 +210,7 @@ packages/app-desktop/gui/MainScreen/commands/showNoteProperties.js
packages/app-desktop/gui/MainScreen/commands/showPrompt.js
packages/app-desktop/gui/MainScreen/commands/showShareFolderDialog.js
packages/app-desktop/gui/MainScreen/commands/showShareNoteDialog.js
+packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.test.js
packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.js
packages/app-desktop/gui/MainScreen/commands/toggleEditors.js
packages/app-desktop/gui/MainScreen/commands/toggleLayoutMoveMode.js
diff --git a/.yarn/patches/husky-npm-3.1.0-5cc13e4e34.patch b/.yarn/patches/husky-npm-3.1.0-5cc13e4e34.patch
new file mode 100644
index 000000000..8c5a1e0d6
--- /dev/null
+++ b/.yarn/patches/husky-npm-3.1.0-5cc13e4e34.patch
@@ -0,0 +1,33 @@
+diff --git a/lib/runner/index.js b/lib/runner/index.js
+index 87e3b3957619728e3ed1ca61e2d83df1c49f928f..6d5ab905415da0577341c8f5b67d4806adcf7549 100644
+--- a/lib/runner/index.js
++++ b/lib/runner/index.js
+@@ -68,15 +68,19 @@ function run([, scriptPath, hookName = '', HUSKY_GIT_PARAMS], getStdinFn = get_s
+ return 0;
+ }
+ catch (err) {
+- const noVerifyMessage = [
+- 'commit-msg',
+- 'pre-commit',
+- 'pre-rebase',
+- 'pre-push'
+- ].includes(hookName)
+- ? '(add --no-verify to bypass)'
+- : '(cannot be bypassed with --no-verify due to Git specs)';
+- console.log(`husky > ${hookName} hook failed ${noVerifyMessage}`);
++ // We do not want to print this "add --no-verify to bypass" message because that's
++ // literally what some developers do instead of trying to fix the errors.
++
++ // const noVerifyMessage = [
++ // 'commit-msg',
++ // 'pre-commit',
++ // 'pre-rebase',
++ // 'pre-push'
++ // ].includes(hookName)
++ // ? '(add --no-verify to bypass)'
++ // : '(cannot be bypassed with --no-verify due to Git specs)';
++
++ console.log(`husky > ${hookName} hook failed (Please fix the errors listed above and try again)`);
+ return err.code;
+ }
+ });
diff --git a/README.md b/README.md
index 6bf0e1c8f..6ff4ca106 100644
--- a/README.md
+++ b/README.md
@@ -39,11 +39,12 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read
| | | | |
| :---: | :---: | :---: | :---: |
-| [avanderberg](https://github.com/avanderberg) | [chr15m](https://github.com/chr15m) | [CyberXZT](https://github.com/CyberXZT) | [dbrandonjohnson](https://github.com/dbrandonjohnson) |
-| [dchecks](https://github.com/dchecks) | [fats](https://github.com/fats) | [Galliver7](https://github.com/Galliver7) | [Hegghammer](https://github.com/Hegghammer) |
-| [jknowles](https://github.com/jknowles) | [KentBrockman](https://github.com/KentBrockman) | [konishi-t](https://github.com/konishi-t) | [marcdw1289](https://github.com/marcdw1289) |
-| [matmoly](https://github.com/matmoly) | [maxtruxa](https://github.com/maxtruxa) | [mu88](https://github.com/mu88) | [saarantras](https://github.com/saarantras) |
-| [sif](https://github.com/sif) | [taskcruncher](https://github.com/taskcruncher) | [tateisu](https://github.com/tateisu) | |
+| [andypiper](https://github.com/andypiper) | [avanderberg](https://github.com/avanderberg) | [chr15m](https://github.com/chr15m) | [CyberXZT](https://github.com/CyberXZT) |
+| [dbrandonjohnson](https://github.com/dbrandonjohnson) | [dchecks](https://github.com/dchecks) | [fats](https://github.com/fats) | [Galliver7](https://github.com/Galliver7) |
+| [Hegghammer](https://github.com/Hegghammer) | [jamesandariese](https://github.com/jamesandariese) | [jknowles](https://github.com/jknowles) | [KentBrockman](https://github.com/KentBrockman) |
+| [konishi-t](https://github.com/konishi-t) | [marcdw1289](https://github.com/marcdw1289) | [matmoly](https://github.com/matmoly) | [maxtruxa](https://github.com/maxtruxa) |
+| [mu88](https://github.com/mu88) | [saarantras](https://github.com/saarantras) | [sif](https://github.com/sif) | [taskcruncher](https://github.com/taskcruncher) |
+| [tateisu](https://github.com/tateisu) | | | |
# Community
diff --git a/cspell.json b/cspell.json
index fb618b0fd..da09f745e 100644
--- a/cspell.json
+++ b/cspell.json
@@ -1,7 +1,13 @@
{
"version": "0.2",
"language": "en_GB",
+ "ignoreRegExpList": [
+ "\\[.*?\\]\\(https:\\/\\/github.com\\/.*?\\)",
+ "by .*?\\)",
+ "\\| (.*?) \\| \\d\\d%"
+ ],
"ignorePaths": [
+ "**/*.d.ts",
"**/*.min.*",
"**/*.svg",
"/_mydocs",
@@ -11,7 +17,10 @@
"/Assets",
"/packages/app-cli/app/fuzzing.js",
"/packages/app-cli/build",
+ "/packages/app-cli/tests/enex_to_md/",
+ "/packages/app-cli/tests/html_to_md/",
"/packages/app-cli/tests/support",
+ "/packages/app-cli/tests/sync",
"/packages/app-cli/tests/test data",
"/packages/app-cli/tests/tmp",
"/packages/app-clipper/content_scripts/JSDOMParser.js",
@@ -20,14 +29,24 @@
"/packages/app-clipper/popup/build/js/0.chunk.js",
"/packages/app-clipper/popup/build/js/bundle.js",
"/packages/app-clipper/popup/build/js/main.chunk.js",
- "/packages/app-clipper/popup/build/js/main.chunk.js",
"/packages/app-clipper/popup/config",
+ "/packages/app-desktop/build/",
+ "/packages/app-desktop/utils/checkForUpdatesUtilsTestData.ts",
"/packages/app-desktop/vendor/",
+ "/packages/app-mobile/ios/Pods/",
+ "/packages/app-mobile/lib/rnInjectedJs",
"/packages/app-mobile/pluginAssets",
+ "/packages/app-mobile/utils/fs-driver/runOnDeviceTests.ts",
+ "/packages/default-plugins/plugin-sources/",
+ "/packages/doc-builder/build",
+ "/packages/doc-builder/help/",
+ "/packages/doc-builder/i18n/",
+ "/packages/doc-builder/news/",
"/packages/fork-sax/examples",
"/packages/fork-sax/lib/sax.js",
"/packages/fork-sax/test",
"/packages/fork-uslug",
+ "/packages/generator-joplin/generators/app/templates/api/",
"/packages/lib/locales",
"/packages/lib/mime-utils-types.js",
"/packages/lib/parameters.js",
@@ -36,919 +55,38 @@
"/packages/lib/services/joplinServer/personalizedUserContentBaseUrl.ts",
"/packages/lib/vendor",
"/packages/lib/welcomeAssets.js",
+ "/packages/renderer/highlight.ts",
+ "/packages/server/src/utils/testing/randomWords.ts",
"/packages/turndown-plugin-gfm/config",
"/packages/turndown/config",
+ "/readme/_i18n",
+ "/readme/about/changelog/desktop.md",
+ "/readme/i18n",
+ "cspell.json",
"node_modules"
],
- "words": [
- "aàáâãäåāą",
- "AÀÁÂÃÄÅĀĄ",
- "abbrev",
- "ABCDEFGHIJ",
- "Abhishek",
- "Abkhazian",
- "accel",
- "accum",
- "actualkeyword",
- "adata",
- "advlist",
- "AGSFE",
- "Aland",
- "Åland",
- "alertbanner",
- "Allaire",
- "alse",
- "altool",
- "aman",
- "ambrt",
- "Amharic",
- "amothc",
- "andrejilderda",
- "anki",
- "Antarctique",
- "antarctiques",
- "Antártico",
- "anymore",
- "apidoc",
- "appiconset",
- "applewebkit",
- "approot",
- "arableague",
- "Aragonés",
- "ARITIM",
- "armeabi",
- "asterix",
- "atest",
- "atestb",
- "attribname",
- "attribvalue",
- "authcode",
- "autocompleteitem",
- "autocompleter",
- "Autocompleter",
- "AUTOEXEC",
- "autohide",
- "Avenir",
- "Ayiti",
- "azamah",
- "Azərbaycan",
- "backoff",
- "Bangla",
- "Bêafrîka",
- "beforeinput",
- "België",
- "Belgien",
- "Belgique",
- "Bénin",
- "Bhutani",
- "bibtex",
- "Bihari",
- "Bislama",
- "blabla",
- "blablablabla",
- "boohay",
- "Bosna",
- "Bouvet",
- "Bouvetøya",
- "browserslist",
- "bthqu",
- "btns",
- "Bulibiya",
- "bullist",
- "bulma",
- "Byelorussian",
- "calebjohn",
- "Calédonie",
- "Caligraphic",
- "callsites",
- "Cameroun",
- "cantdothat",
- "Capslock",
- "cardcontainer",
- "cardimage",
- "cardmenuitem",
- "cardtext",
- "Caribisch",
- "CAUTOEXEC",
- "cçćč",
- "CÇĆČ",
- "cdataend",
- "cdatastart",
- "cdot",
- "ceaf",
- "centrafricaine",
- "Centrafrican",
- "Česká",
- "changedtitle",
- "charcodes",
- "checkboxclick",
- "checkmark",
- "chemfive",
- "choiceitem",
- "chromedriver",
- "chromeframe",
- "chromeos",
- "Città",
- "Cmds",
- "codepoint",
- "colorinput",
- "colorpicker",
- "colorswatch",
- "colspan",
- "committerdate",
- "commmmmand",
- "commonmark",
- "COMMONMARK",
- "Comores",
- "compositionend",
- "compositionstart",
- "compositionupdate",
- "conflicter",
- "contenteditable",
- "contextform",
- "contextformbutton",
- "contextformtogglebutton",
- "contextkey",
- "contexttoolbar",
- "continuelist",
- "Contrl",
- "Conv",
- "convo",
- "copytags",
- "cozic",
- "Cozic",
- "createdb",
- "Creds",
- "Crna",
- "cronspec",
- "cros",
- "crypted",
- "Curaçao",
- "curso",
- "customeditor",
- "customkeymap",
- "cyingfan",
- "d'Ivoire",
- "Danmark",
- "Dansk",
- "dataimg",
- "datauri",
- "Datauri",
- "datetime",
- "Datetime",
- "davris",
- "dbuuid",
- "DDTHH",
- "deflist",
- "deinit",
- "Démocratique",
- "deselector",
- "deuxième",
- "dflt",
- "dialogbox",
- "dialogs",
- "Dialogs",
- "DIALOGS",
- "Distill",
- "dists",
- "docid",
- "docsize",
- "doctypes",
- "doesnotwork",
- "doesntexist",
- "doesntlookright",
- "domelementtype",
- "domhandler",
- "Dominicana",
- "domutils",
- "DONATELINKS",
- "downarrow",
- "dragdrop",
- "draggesture",
- "dünn",
- "dylib",
- "dynamiclib",
- "ecuatorial",
- "eèéêëěēę",
- "EÈÉÊËĚĒĘ",
- "Eesti",
- "effet",
- "efgh",
- "égalité",
- "Éire",
- "elem",
- "elementpath",
- "elems",
- "ellipsize",
- "ELOCKED",
- "encryptable",
- "endregion",
- "enex",
- "Enex",
- "ENEX",
- "enumber",
- "eqeqeq",
- "équatoriale",
- "Erro",
- "errorish",
- "escapeplus",
- "eslintignore",
- "España",
- "étiquette",
- "EUNSPECIFIED",
- "eventname",
- "evermeet",
- "evernote",
- "Evernote",
- "execa",
- "expando",
- "expirable",
- "Expirable",
- "expval",
- "Færøerne",
- "Fahrräder",
- "FAILSAFE",
- "fallbacks",
- "fancymenuitem",
- "fancytype",
- "favorites",
- "Fiber",
- "filepicker",
- "folderid",
- "foldl",
- "fontawesome",
- "fontface",
- "forall",
- "forcewake",
- "Føroyar",
- "fortawesome",
- "française",
- "françaises",
- "Gabuutih",
- "gedit",
- "geoip",
- "Geoip",
- "geoloc",
- "geoplugin",
- "getlastmodified",
- "gettext",
- "githubusercontent",
- "Gora",
- "gotchas",
- "gradlew",
- "Grønland",
- "grouptoolbarbutton",
- "Gruber",
- "gsoc",
- "gttest",
- "Guåhån",
- "guarentee",
- "guarentees",
- "Guiena",
- "Guiné",
- "Guinée",
- "gulpfile",
- "Guyane",
- "gvim",
- "Haïti",
- "hanlder",
- "Hausa",
- "headerless",
- "Heisenbug",
- "Hercegovina",
- "hift",
- "highjack",
- "highlited",
- "historyhas",
- "HMRKG",
- "hoge",
- "homenote",
- "hotfolder",
- "Howver",
- "hpagent",
- "Hrvatska",
- "htmlentities",
- "htmlfile",
- "htmlpack",
- "htmlpanel",
- "ʻĀirani",
- "icns",
- "iconset",
- "iconutil",
- "Iforgot",
- "iframes",
- "ihack",
- "iife",
- "iìíîïī",
- "IÌÍÎÏĪ",
- "ijkl",
- "imagelink",
- "imagetools",
- "immer",
- "iname",
- "Incl",
- "infint",
- "inflim",
- "infty",
- "inputi",
- "inserttable",
- "Interlingue",
- "Interp",
- "interupting",
- "Inteval",
- "Inuktitut",
- "Inupiak",
- "Invididual",
- "IOERR",
- "Ionicons",
- "IPHONEOS",
- "ipify",
- "ipwhois",
- "iscompleted",
- "Ísland",
- "Italiano",
- "Itoophiyaa",
- "itsgone",
- "itunes",
- "Jabuuti",
- "jackgruber",
- "joeattardi",
- "jopext",
- "joplinapp",
- "JOPLINAPP",
- "joplincloud",
- "joplindev",
- "JOPLINMOD",
- "joplintest",
- "jsbundles",
- "justtesting",
- "Kalaallit",
- "kalba",
- "kanban",
- "Kashmiri",
- "katex",
- "keychain",
- "keycodes",
- "keymaps",
- "keytar",
- "Kibris",
- "Kinyarwanda",
- "Kirundi",
- "Ködörösêse",
- "Komori",
- "Kpck",
- "Kūki",
- "Laothian",
- "lastmod",
- "Latvija",
- "lcov",
- "leaft",
- "leftarrow",
- "leftequilibrium",
- "leftrightarrow",
- "Lettish",
- "Lëtzebuerg",
- "Levithan",
- "Liban",
- "libz",
- "Lietuva",
- "Lietuvių",
- "lineheight",
- "Lingala",
- "linkg",
- "linkurl",
- "listbox",
- "listfile",
- "listpreview",
- "loglevel",
- "longclick",
- "longpress",
- "longpresscancel",
- "looooooong",
- "ltrim",
- "Luxemburg",
- "Maarten",
- "Madagasikara",
- "Magyarország",
- "majax",
- "Mardown",
- "markdowncalc",
- "Maroc",
- "MASTERKEY",
- "matchinfo",
- "mathchoice",
- "mathjax",
- "Mathjax",
- "MATHJAX",
- "mathllap",
- "mathml",
- "mathrlap",
- "mathrm",
- "Mauritanie",
- "Maxiumm",
- "Mayen",
- "mchem",
- "mechanim",
- "mediumtext",
- "menubutton",
- "mergeff",
- "Metadatas",
- "México",
- "mhchem",
- "middlewares",
- "migth",
- "mkbook",
- "MKCOL",
- "mkdirp",
- "mknote",
- "mktodo",
- "MMYY",
- "modifié",
- "monokai",
- "MONOSPACE",
- "msgctxt",
- "msgfmt",
- "msgmerge",
- "msgstr",
- "msleep",
- "mtext",
- "mult",
- "multicursor",
- "multimarkdown",
- "multimd",
- "multistatus",
- "multitable",
- "mybucket",
- "mydir",
- "myfile",
- "mynote",
- "myplugin",
- "mytag",
- "mytaga",
- "mytagb",
- "mytagc",
- "mytagd",
- "mytest",
- "mytoken",
- "myvalue",
- "nanoid",
- "Neaus",
- "Nederlands",
- "nestedmenuitem",
- "newone",
- "Nextcloud",
- "njstrace",
- "nñňń",
- "NÑŇŃ",
- "NOCASE",
- "nodechange",
- "nodir",
- "noexpand",
- "nojs",
- "nolongershared",
- "nonlatin",
- "NONLATIN",
- "Noreg",
- "Norge",
- "nospecialcharacters",
- "notanumber",
- "notarization",
- "notetags",
- "Notif",
- "notindexed",
- "notthere",
- "nounce",
- "Nounce",
- "Nounces",
- "npmignore",
- "numadd",
- "numbersareok",
- "numdec",
- "numdiv",
- "numlist",
- "Numlock",
- "nummult",
- "numsub",
- "Nunaat",
- "obelix",
- "odata",
- "ohno",
- "OHNO",
- "oldppk",
- "onattribdata",
- "onattribend",
- "onattribname",
- "onattribute",
- "oncdata",
- "oncdataend",
- "oncdatastart",
- "onclosetag",
- "oncomment",
- "oncommentend",
- "ondeclaration",
- "onedrive",
- "onelink",
- "onformat",
- "onmatch",
- "onopentag",
- "onopentagend",
- "onopentagname",
- "onparserinit",
- "onprocessinginstruction",
- "onselfclosingtag",
- "ontext",
- "oòóôõöøō",
- "OÒÓÔÕÖØŌ",
- "opentag",
- "opentagname",
- "Opptionn",
- "orignal",
- "Oromo",
- "Österreich",
- "otherpackage",
- "outdented",
- "overidding",
- "overriden",
- "padd",
- "pandoc",
- "paperclip",
- "passthrough",
- "Päth",
- "Pbuild",
- "pbxproj",
- "pcmag",
- "pcnalx",
- "pddv",
- "Pehr",
- "Percents",
- "père",
- "Perú",
- "pfff",
- "PGPASSWORD",
- "pidfile",
- "PLUGINLEGACY",
- "pocount",
- "Polska",
- "Polski",
- "Polynésie",
- "Português",
- "Potoczny's",
- "powerpoint",
- "Prakash",
- "precommit",
- "pred",
- "preg",
- "prerelease",
- "Prerelease",
- "presigner",
- "prettycron",
- "pricetag",
- "Príncipe",
- "privkey",
- "processinginstruction",
- "programatically",
- "propfind",
- "PROPFIND",
- "propname",
- "propstat",
- "protcol",
- "pseudoclass",
- "pseudos",
- "Pushto",
- "quot",
- "qwer",
- "raisebox",
- "rbga",
- "readerable",
- "Readerable",
- "READERABLE",
- "Redownload",
- "reencrypt",
- "reencrypted",
- "Reencrypting",
- "reencrypts",
- "regexes",
- "Regexs",
- "Relavent",
- "relayouted",
- "rels",
- "renamings",
- "renderered",
- "Renderered",
- "República",
- "republika",
- "République",
- "requestheaders",
- "resourcetype",
- "resynced",
- "Rhaeto",
- "rightarrow",
- "rightequilibrium",
- "rightleftarrows",
- "rightleftharpoons",
- "rmbook",
- "rmnote",
- "rmusin",
- "rnfs",
- "RNFS",
- "robocopy",
- "Roboto",
- "România",
- "roule",
- "rowid",
- "ROWID",
- "ROWIDs",
- "rowspan",
- "rseidelsohn",
- "rtrim",
- "safeext",
- "salut",
- "Sangho",
- "sasss",
- "SAVEPOINT",
- "schtroumpf",
- "Schweiz",
- "Scrolllock",
- "scrollmap",
- "seafdav",
- "Seafile",
- "searchengine",
- "searchlimit",
- "SEARCHOVERLAY",
- "securerandom",
- "segdir",
- "selectbox",
- "Sénégal",
- "Serializers",
- "setext",
- "settingschema",
- "shantanugoel",
- "sharee",
- "Shiftt",
- "Shoft",
- "shouldntendwithit",
- "shouldstartwiththis",
- "Shqip",
- "Shqipëria",
- "Sicen",
- "simplemath",
- "Siswati",
- "sizeinput",
- "SJCL",
- "Slovenčina",
- "Slovenija",
- "Slovensko",
- "softbreaks",
- "Solarised",
- "SOLARIZED",
- "someid",
- "somewhereelse",
- "sourceurl",
- "SPACEBAR",
- "spaceno",
- "Spacify",
- "spdfgh",
- "spellfix",
- "sphemy",
- "splitbutton",
- "sprintf",
- "sqlts",
- "srcfolder",
- "SSSZ",
- "starttls",
- "Starttls",
- "stepsize",
- "stevenlevithan",
- "stex",
- "stilltryingtohack",
- "strack",
- "Stringifiable",
- "subdir",
- "subl",
- "Suomi",
- "Sūriyya",
- "Svenska",
- "Sverige",
- "svgs",
- "Svizra",
- "Svizzera",
- "synclock",
- "synclog",
- "syswide",
- "syswidecas",
- "taboverride",
- "tabpanel",
- "taga",
- "tagb",
- "tagc",
- "Tajik",
- "takesover",
- "targetfolder",
- "Tchad",
- "Teardown",
- "termi",
- "termutils",
- "Terres",
- "Tessarek",
- "tessus",
- "Testb",
- "testcreate",
- "testexportfolder",
- "testingconnection",
- "testingkeychain",
- "testunit",
- "texify",
- "Texify",
- "textareas",
- "textexportnote",
- "textstyle",
- "thaaaaaaan",
- "thatsok",
- "thatsreallylongthatsreallylongthatsreallylongthats",
- "thatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylong",
- "Thevenard",
- "thisisfine",
- "Thmmss",
- "Tiếng",
- "Tigrinya",
- "tiiitlllle",
- "tinymce",
- "titi",
- "titletitle",
- "tkwidget",
- "tkwidgets",
- "Todos",
- "togglebutton",
- "togglemenuitem",
- "toolip",
- "tooshort",
- "treymo",
- "tripledash",
- "tsmerge",
- "Tsonga",
- "tttest",
- "Tunisie",
- "Türkçe",
- "Türkiye",
- "Türkmenistan",
- "turndown",
- "Turndown",
- "TWCO",
- "typeahead",
- "Typora",
- "tzip",
- "uastring",
- "uglifycss",
- "uglifyjs",
- "Uighur",
- "unconflicted",
- "underbrace",
- "Undos",
- "unescaping",
- "unhighlighted",
- "unixlike",
- "unmocked",
- "unserialize",
- "unserialized",
- "unserializes",
- "unserializing",
- "unshares",
- "unsharing",
- "unusued",
- "uparrow",
- "uphy",
- "urlconverter",
- "urlinput",
- "userchrome",
- "usercontent",
- "userstyle",
- "uslug",
- "Ustd",
- "utems",
- "uuidgen",
- "uuidv",
- "uùúûüůū",
- "UÙÚÛÜŮŪ",
- "valign",
- "Valign",
- "vars",
- "Vars",
- "Vaticano",
- "vers",
- "verylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongid",
- "veryverylongclientidveryverylongclientidveryverylongclientidveryverylongclientid",
- "veryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitleveryverylongtitle",
- "Việt",
- "viewbox",
- "Volapuk",
- "Volívia",
- "votearrow",
- "webclipper",
- "webdav",
- "webfonts",
- "whitespaces",
- "widder",
- "Wifi",
- "Withflags",
- "Wolof",
- "WONTFIX",
- "wrongclienttype",
- "wrongpassword",
- "wrongtype",
- "Wuliwya",
- "wxyz",
- "xcallbackurl",
- "xcassets",
- "xcodeproj",
- "xcrun",
- "xgettext",
- "xlink",
- "xzvf",
- "yarg",
- "yosay",
- "yufzkns",
- "YYYYMMDDTHH",
- "zxcvbn",
- "zžżź",
- "ZŽŻŹ",
- "Ελλάδα",
- "Ελληνικά",
- "Κύπρος",
- "Агентство",
- "Антарктике",
- "Беларусь",
- "България",
- "Гора",
- "језик",
- "Казахстан",
- "Киргизия",
- "Книги",
- "Кыргызстан",
- "Қазақстан",
- "Македонија",
- "Молдавия",
- "Монгол",
- "номер",
- "рейтер",
- "Рейтер",
- "Россия",
- "Русский",
- "Северна",
- "сообщило",
- "СООБЩИЛО",
- "Србија",
- "српски",
- "Україна",
- "Црна",
- "საქართველო",
- "Հայաստան",
- "ישראל",
- "עיברית",
- "إرتريا",
- "اسلامي",
- "اسلامی",
- "افغانستان",
- "الأُرْدُن",
- "الإمارات",
- "البحرين",
- "الجزائر",
- "السعودية",
- "السودان",
- "الصومال",
- "العراق",
- "العربيّة",
- "ﺍﻟﻘﻤﺮي",
- "الكويت",
- "المتّحدة",
- "المغرب",
- "اليَمَن",
- "ایران",
- "پاکستان",
- "تشاد",
- "تونس",
- "جمهوری",
- "جيبوتي",
- "دولة",
- "دولتدولت",
- "سلطنة",
- "سوريا",
- "عُمان",
- "لبنان",
- "ليبيا",
- "موريتانيا",
- "ⵍⵎⵖⵔⵉⴱ",
- "ኢትዮጵያ",
- "ኤርትራ",
- "भारत",
- "গণপ্রজাতন্ত্রী",
- "লাদেশ",
- "இலங்கை",
- "ලංකා",
- "คือค",
- "คือคนไทย",
- "ประเทศไทย",
- "ປະຊາຊົນລາວ",
- "မြန်မာ",
- "កម្ពុជា"
- ]
+ "dictionaryDefinitions": [
+ {
+ "name": "dictionary1",
+ "path": "packages/tools/cspell/dictionary1.txt"
+ },
+ {
+ "name": "dictionary2",
+ "path": "packages/tools/cspell/dictionary2.txt"
+ },
+ {
+ "name": "dictionary3",
+ "path": "packages/tools/cspell/dictionary3.txt"
+ },
+ {
+ "name": "dictionary4",
+ "path": "packages/tools/cspell/dictionary4.txt"
+ }
+ ],
+ "dictionaries": [
+ "dictionary1",
+ "dictionary2",
+ "dictionary3",
+ "dictionary4"
+ ]
}
diff --git a/lint-staged.config.js b/lint-staged.config.js
index ec2637268..4b350298d 100644
--- a/lint-staged.config.js
+++ b/lint-staged.config.js
@@ -1,19 +1,27 @@
module.exports = {
- // Don't compile when committing as it will process all TS files in the
- // monorepo, which is too slow. Errors should be checked during development
- // using `npm run watch`.
+ // # About TypeScript compilation
+ //
+ // Don't compile when committing as it will process all TS files in the monorepo, which is too
+ // slow. Errors should be checked during development using `yarn watch`.
//
// Or if we add this back, we could do something like this:
// https://stackoverflow.com/a/44748041/561309
//
- // The script would check where the TS file is located, then use the right
- // tsconfig.json file along with the tsconfig override.
+ // The script would check where the TS file is located, then use the right tsconfig.json file
+ // along with the tsconfig override.
//
- // '**/*.ts?(x)': () => 'npm run tsc',
- '*.{js,jsx,ts,tsx}': [
- 'yarn checkIgnoredFiles',
- // 'yarn checkLibPaths',
- 'yarn packageJsonLint',
- 'yarn linter-precommit',
- ],
+ // # Running tasks in parallel
+ //
+ // lint-staged does not allow running concurrent tasks for the same extension, because multiple
+ // tasks might modify the same files. This doesn't apply to us because only one task modifies
+ // files (the linter task) while others only notify about errors. So to go around this we add
+ // this fake extension "task?" to make lint-staged think those are different extension tasks
+ // that can run in parallel.
+ //
+ // See https://github.com/lint-staged/lint-staged/issues/934#issuecomment-743299357
+ '*.{js,jsx,ts,tsx,task1}': 'yarn checkIgnoredFiles',
+ '*.{js,jsx,ts,tsx,task2}': 'yarn spellcheck',
+ '*.{js,jsx,ts,tsx,task3}': 'yarn packageJsonLint',
+ '*.{js,jsx,ts,tsx,task4}': 'yarn linter-precommit',
+ '*.{md,mdx}': 'yarn spellcheck',
};
diff --git a/package.json b/package.json
index fe935fdee..694d34f0e 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,6 @@
"crowdin": "crowdin",
"crowdinDownload": "crowdin download",
"crowdinUpload": "crowdin upload",
- "cspell": "cspell",
"dependencyTree": "madge",
"generateTypes": "node packages/tools/generate-database-types",
"linkChecker": "linkchecker https://joplinapp.org/ && linkchecker --check-extern https://joplinapp.org/api/references/plugin_api/classes/joplin.html",
@@ -65,7 +64,7 @@
},
"husky": {
"hooks": {
- "pre-commit": "lint-staged"
+ "pre-commit": "yarn lint-staged"
}
},
"devDependencies": {
@@ -108,6 +107,7 @@
"react-native@0.71.10": "patch:react-native@npm%3A0.71.10#./.yarn/patches/react-native-animation-fix/react-native-npm-0.71.10-f9c32562d8.patch",
"nanoid": "patch:nanoid@npm%3A3.3.7#./.yarn/patches/nanoid-npm-3.3.7-98824ba130.patch",
"pdfjs-dist": "patch:pdfjs-dist@npm%3A3.11.174#./.yarn/patches/pdfjs-dist-npm-3.11.174-67f2fee6d6.patch",
- "@react-native-community/slider": "patch:@react-native-community/slider@npm%3A4.4.4#./.yarn/patches/@react-native-community-slider-npm-4.4.4-d78e472f48.patch"
+ "@react-native-community/slider": "patch:@react-native-community/slider@npm%3A4.4.4#./.yarn/patches/@react-native-community-slider-npm-4.4.4-d78e472f48.patch",
+ "husky": "patch:husky@npm%3A3.1.0#./.yarn/patches/husky-npm-3.1.0-5cc13e4e34.patch"
}
}
diff --git a/packages/app-cli/app/command-apidoc.ts b/packages/app-cli/app/command-apidoc.ts
index 4d4f0d3fb..2b794dc5b 100644
--- a/packages/app-cli/app/command-apidoc.ts
+++ b/packages/app-cli/app/command-apidoc.ts
@@ -82,7 +82,7 @@ class Command extends BaseCommand {
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('To prevent unauthorised applications from accessing the API, the calls must be authenticated. 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('');
lines.push('This would be an example of valid cURL call using a token:');
lines.push('');
@@ -149,7 +149,7 @@ class Command extends BaseCommand {
lines.push('');
lines.push('```shell\ncurl http://localhost:41184/notes?order_by=updated_time&order_dir=ASC&limit=10&page=2\n```');
lines.push('');
- lines.push('Eventually you will get some results that do not contain an "has_more" paramater, at which point you will have retrieved all the results');
+ lines.push('Eventually you will get some results that do not contain an "has_more" parameter, at which point you will have retrieved all the results');
lines.push('');
lines.push('As an example the pseudo-code below could be used to fetch all the notes:');
lines.push('');
@@ -199,7 +199,7 @@ async function fetchAllNotes() {
lines.push('## Item type IDs');
lines.push('');
- lines.push('Item type IDs might be refered to in certain object you will retrieve from the API. This is the correspondance between name and ID:');
+ lines.push('Item type IDs might be referred to in certain objects you will retrieve from the API. This is the correspondence between name and ID:');
lines.push('');
lines.push('Name | Value');
lines.push('---- | -----');
diff --git a/packages/app-cli/app/command-sync.ts b/packages/app-cli/app/command-sync.ts
index 468752aa0..f6f90c4ea 100644
--- a/packages/app-cli/app/command-sync.ts
+++ b/packages/app-cli/app/command-sync.ts
@@ -86,7 +86,7 @@ class Command extends BaseCommand {
return true;
}
- this.stdout(_('Not authentified with %s. Please provide any missing credentials.', syncTargetMd.label));
+ this.stdout(_('Not authenticated with %s. Please provide any missing credentials.', syncTargetMd.label));
return false;
}
diff --git a/packages/app-cli/tests/services/keychain/KeychainService.ts b/packages/app-cli/tests/services/keychain/KeychainService.ts
index cff8d3d86..3881931e0 100644
--- a/packages/app-cli/tests/services/keychain/KeychainService.ts
+++ b/packages/app-cli/tests/services/keychain/KeychainService.ts
@@ -52,7 +52,7 @@ describeIfCompatible('services_KeychainService', () => {
}));
it('should delete db settings if they have been saved in keychain', (async () => {
- // First save some secure settings and make sure it ends up in the databse
+ // First save some secure settings and make sure it ends up in the database
KeychainService.instance().enabled = false;
Setting.setValue('sync.5.password', 'password');
diff --git a/packages/app-clipper/background.js b/packages/app-clipper/background.js
index 295d775e6..8fec06044 100644
--- a/packages/app-clipper/background.js
+++ b/packages/app-clipper/background.js
@@ -26,7 +26,7 @@ async function browserCaptureVisibleTabs(windowId) {
// This is supposed to be the default quality, but in fact Firefox 82+
// clearly uses a much lower quality, closer to 20 or 30, so we have to
- // set it here explicitely.
+ // set it here explicitly.
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/extensionTypes/ImageDetails
// https://discourse.joplinapp.org/t/clip-screenshot-image-quality/12302/4
quality: 92,
diff --git a/packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx b/packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx
index 1a54cf5c9..350a858ac 100644
--- a/packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx
+++ b/packages/app-desktop/gui/KeymapConfig/KeymapConfigScreen.tsx
@@ -78,7 +78,7 @@ export const KeymapConfigScreen = ({ themeId }: KeymapConfigScreenProps) => {
// KeymapService is already synchronized with the in-state keymap
await keymapService.saveCustomKeymap(filePath);
} catch (error) {
- bridge().showerrororMessageBox(error.message);
+ bridge().showErrorMessageBox(error.message);
}
}
};
diff --git a/packages/app-desktop/gui/MainScreen/MainScreen.tsx b/packages/app-desktop/gui/MainScreen/MainScreen.tsx
index bd81cf53a..bb9e73932 100644
--- a/packages/app-desktop/gui/MainScreen/MainScreen.tsx
+++ b/packages/app-desktop/gui/MainScreen/MainScreen.tsx
@@ -237,7 +237,7 @@ class MainScreenComponent extends React.Component {
try {
output = loadLayout(Object.keys(userLayout).length ? userLayout : null, defaultLayout, rootLayoutSize);
- // For unclear reasons, layout items sometimes end up witout a key.
+ // For unclear reasons, layout items sometimes end up without a key.
// In that case, we can't do anything with them, so remove them
// here. It could be due to the deprecated plugin API, which allowed
// creating panel without a key, although in this case it should
@@ -264,7 +264,7 @@ class MainScreenComponent extends React.Component {
public setupAppCloseHandling() {
this.waitForNotesSavedIID_ = null;
- // This event is dispached from the main process when the app is about
+ // This event is dispatched from the main process when the app is about
// to close. The renderer process must respond with the "appCloseReply"
// and tell the main process whether the app can really be closed or not.
// For example, it cannot be closed right away if a note is being saved.
diff --git a/packages/app-desktop/gui/MainScreen/commands/setTags.ts b/packages/app-desktop/gui/MainScreen/commands/setTags.ts
index 494bf1311..46b004b6f 100644
--- a/packages/app-desktop/gui/MainScreen/commands/setTags.ts
+++ b/packages/app-desktop/gui/MainScreen/commands/setTags.ts
@@ -19,7 +19,7 @@ export const runtime = (comp: any): CommandRuntime => {
return { value: a.id, label: a.title };
})
.sort((a: any, b: any) => {
- // sensitivity accent will treat accented characters as differemt
+ // sensitivity accent will treat accented characters as different
// but treats caps as equal
return a.label.localeCompare(b.label, undefined, { sensitivity: 'accent' });
});
@@ -28,7 +28,7 @@ export const runtime = (comp: any): CommandRuntime => {
return { value: a.id, label: a.title };
})
.sort((a: any, b: any) => {
- // sensitivity accent will treat accented characters as differemt
+ // sensitivity accent will treat accented characters as different
// but treats caps as equal
return a.label.localeCompare(b.label, undefined, { sensitivity: 'accent' });
});
diff --git a/packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.test.ts b/packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.test.ts
new file mode 100644
index 000000000..a9403eb65
--- /dev/null
+++ b/packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.test.ts
@@ -0,0 +1,51 @@
+import { runtime } from './showSpellCheckerMenu';
+import { AppState } from '../../../app.reducer';
+
+jest.mock('../../../services/bridge', () => ({
+ __esModule: true,
+ default: () => ({
+ Menu: {
+ buildFromTemplate: jest.fn().mockReturnValue({
+ popup: jest.fn(),
+ }),
+ },
+ }),
+}));
+
+describe('mapStateToTitle', () => {
+
+ test('should return null if spellchecker.enabled is false', () => {
+
+ const mockState: Partial = {
+ settings: {
+ 'spellChecker.enabled': false,
+ 'spellChecker.languages': ['en-GB'],
+ },
+ };
+ const result = runtime().mapStateToTitle(mockState);
+ expect(result).toBeNull();
+ });
+
+ test('should return null if spellChecker.languages is empty', () => {
+ const mockState: Partial = {
+ settings: {
+ 'spellChecker.enabled': true,
+ 'spellChecker.languages': [],
+ },
+ };
+ const result = runtime().mapStateToTitle(mockState);
+ expect(result).toBeNull();
+ });
+
+ test('should return list of countryDisplayName with correct format', () => {
+ const mockState: Partial = {
+ settings: {
+ 'spellChecker.enabled': true,
+ 'spellChecker.languages': ['en-GB', 'en-US', 'en-CA', 'es-ES', 'es-MX'],
+ },
+ };
+ const result = runtime().mapStateToTitle(mockState);
+ expect(result).toBe('en, es');
+
+ });
+});
diff --git a/packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.ts b/packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.ts
index f52aaf8d0..8d9dcd452 100644
--- a/packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.ts
+++ b/packages/app-desktop/gui/MainScreen/commands/showSpellCheckerMenu.ts
@@ -30,8 +30,10 @@ export const runtime = (): CommandRuntime => {
const s: string[] = [];
// eslint-disable-next-line github/array-foreach -- Old code before rule was applied
languages.forEach((language: string) => {
- s.push(language.split('-')[0]);
+ const onlyLanguage = language.split('-')[0];
+ if (!s.includes(onlyLanguage)) { s.push(onlyLanguage); }
});
+
return s.join(', ');
},
};
diff --git a/packages/app-desktop/gui/MenuBar.tsx b/packages/app-desktop/gui/MenuBar.tsx
index aa24c2fb8..c96506979 100644
--- a/packages/app-desktop/gui/MenuBar.tsx
+++ b/packages/app-desktop/gui/MenuBar.tsx
@@ -563,10 +563,10 @@ function useMenu(props: Props) {
const rootMenuFile = {
// Using a dummy entry for macOS here, because first menu
- // becomes 'Joplin' and we need a nenu called 'File' later.
+ // becomes 'Joplin' and we need a menu called 'File' later.
label: shim.isMac() ? '&JoplinMainMenu' : _('&File'),
// `&` before one of the char in the label name mean, that
- // will open this menu. It's needed becase electron
+ // will open this menu. It's needed because electron
// opens the first menu on Alt press if no hotkey assigned.
// Issue: https://github.com/laurent22/joplin/issues/934
submenu: [{
diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts
index 86002e236..6289d8419 100644
--- a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts
+++ b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useContextMenu.ts
@@ -117,7 +117,7 @@ const useContextMenu = (props: ContextMenuProps) => {
// CodeMirror 5 only:
// Typically CodeMirror handles all interactions itself (highlighting etc.)
- // But in the case of clicking a mispelled word, we need electron to handle the click
+ // But in the case of clicking a misspelled word, we need electron to handle the click
// The result is that CodeMirror doesn't know what's been selected and doesn't
// move the cursor into the correct location.
// and when the user selects a new spelling it will be inserted in the wrong location
diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearch.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearch.ts
index 5ea54beb6..942c03106 100644
--- a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearch.ts
+++ b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useEditorSearch.ts
@@ -62,7 +62,7 @@ export default function useEditorSearch(CodeMirror: any) {
}
// Highlights the currently active found work
- // It's possible to get tricky with this fucntions and just use findNext/findPrev
+ // It's possible to get tricky with this functions and just use findNext/findPrev
// but this is fast enough and works more naturally with the current search logic
function highlightSearch(cm: any, searchTerm: RegExp, index: number, scrollTo: boolean, withSelection: boolean) {
const cursor = cm.getSearchCursor(searchTerm);
@@ -135,7 +135,7 @@ export default function useEditorSearch(CodeMirror: any) {
if (error.name !== 'SyntaxError') {
throw error;
}
- // An error of 'Regular expression too large' might occour in the markJs library
+ // An error of 'Regular expression too large' might occur in the markJs library
// when the input is really big, this catch is here to avoid the application crashing
// https://github.com/laurent22/joplin/issues/7634
console.error('Error while trying to highlight words from search: ', error);
diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollHandler.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollHandler.ts
index 1a1443502..d1b5d8ad5 100644
--- a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollHandler.ts
+++ b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollHandler.ts
@@ -115,7 +115,7 @@ export default function useScrollHandler(editorRef: any, webviewRef: any, onScro
if (!isNaN(editorPercent)) {
// when switching to another note, the percent can sometimes be NaN
// this is coming from `gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollUtils.ts`
- // when CodeMirror returns scroll info with heigth == clientHeigth
+ // when CodeMirror returns scroll info with height == clientHeight
// https://github.com/laurent22/joplin/issues/4797
if (!ignored) {
// calculates GUI-independent line-based percent
diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx
index 9174523c0..5b9ded4cf 100644
--- a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx
+++ b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/CodeMirror.tsx
@@ -507,7 +507,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: ForwardedRef {
if (joplinCommandToTinyMceCommands[cmd.name] === true) {
// Already handled in useWindowCommandHandlers.ts
} else if (joplinCommandToTinyMceCommands[cmd.name] === false) {
- // Explicitely not supported
+ // explicitly not supported
} else {
const tinyMceCmd: TinyMceCommand = { ...(joplinCommandToTinyMceCommands[cmd.name] as TinyMceCommand) };
if (!('ui' in tinyMceCmd)) tinyMceCmd.ui = false;
@@ -1126,7 +1126,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
//
// when pasting text with Ctrl+Shift+V, the format should be
// ignored. In this case,
- // event.clopboardData.getData('text/html') returns an empty
+ // event.clipboardData.getData('text/html') returns an empty
// string, but the clipboard.readHTML() still returns the
// formatted text.
const pastedHtml = event.clipboardData.getData('text/html') ? clipboard.readHTML() : '';
diff --git a/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx b/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx
index de9185b38..3176a01cf 100644
--- a/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx
+++ b/packages/app-desktop/gui/NoteEditor/NoteEditor.tsx
@@ -468,7 +468,7 @@ function NoteEditor(props: NoteEditorProps) {
isSafeMode: props.isSafeMode,
useCustomPdfViewer: props.useCustomPdfViewer,
// We need it to identify the context for which media is rendered.
- // It is currently used to remember pdf scroll position for each attacments of each note uniquely.
+ // It is currently used to remember pdf scroll position for each attachments of each note uniquely.
noteId: props.noteId,
};
diff --git a/packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.test.ts b/packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.test.ts
index 0d2b16734..6b6a78443 100644
--- a/packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.test.ts
+++ b/packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.test.ts
@@ -38,7 +38,7 @@ describe('clipboardUtils', () => {
expect(copyableContent.html).toEqual(``);
});
- test('should be able to process mutiple images', () => {
+ test('should be able to process multiple images', () => {
const localImage1 = 'file:///home/some/path/test1.jpg';
const localImage2 = 'file:///home/some/path/test2.jpg';
const localImage3 = 'file:///home/some/path/test3.jpg';
diff --git a/packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.ts b/packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.ts
index 99660398f..2e28da830 100644
--- a/packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.ts
+++ b/packages/app-desktop/gui/NoteEditor/utils/clipboardUtils.ts
@@ -18,7 +18,7 @@ function htmlToMd(): HtmlToMd {
function removeImageUrlAttributes(htmlContent: string): string {
// We need to remove extra url params from the image URLs while copying
- // because some offline edtors do not show the image if there is
+ // because some offline editors do not show the image if there is
// an extra parameter in it's path.
// Related to - https://github.com/laurent22/joplin/issues/4602
const removeParametersFromUrl = (url: string) => {
diff --git a/packages/app-desktop/gui/NoteEditor/utils/useFormNote.ts b/packages/app-desktop/gui/NoteEditor/utils/useFormNote.ts
index 96a330dc8..11e5faae8 100644
--- a/packages/app-desktop/gui/NoteEditor/utils/useFormNote.ts
+++ b/packages/app-desktop/gui/NoteEditor/utils/useFormNote.ts
@@ -75,7 +75,7 @@ export default function useFormNote(dependencies: HookDependencies) {
// Increasing the value of this counter cancels any ongoing note refreshes and starts
// a new refresh.
- const [formNoteRefeshScheduled, setFormNoteRefreshScheduled] = useState(0);
+ const [formNoteRefreshScheduled, setFormNoteRefreshScheduled] = useState(0);
async function initNoteState(n: any) {
let originalCss = '';
@@ -114,7 +114,7 @@ export default function useFormNote(dependencies: HookDependencies) {
}
useEffect(() => {
- if (formNoteRefeshScheduled <= 0) return () => {};
+ if (formNoteRefreshScheduled <= 0) return () => {};
reg.logger().info('Sync has finished and note has never been changed - reloading it');
@@ -141,13 +141,13 @@ export default function useFormNote(dependencies: HookDependencies) {
return () => {
cancelled = true;
};
- }, [formNoteRefeshScheduled, noteId]);
+ }, [formNoteRefreshScheduled, noteId]);
const refreshFormNote = useCallback(() => {
// Increase the counter to cancel any ongoing refresh attempts
// and start a new one.
- setFormNoteRefreshScheduled(formNoteRefeshScheduled + 1);
- }, [formNoteRefeshScheduled]);
+ setFormNoteRefreshScheduled(formNoteRefreshScheduled + 1);
+ }, [formNoteRefreshScheduled]);
useEffect(() => {
// Check that synchronisation has just finished - and
diff --git a/packages/app-desktop/gui/NoteList/utils/useScroll.ts b/packages/app-desktop/gui/NoteList/utils/useScroll.ts
index feecbf41f..450569b79 100644
--- a/packages/app-desktop/gui/NoteList/utils/useScroll.ts
+++ b/packages/app-desktop/gui/NoteList/utils/useScroll.ts
@@ -22,7 +22,7 @@ const useScroll = (itemsPerLine: number, noteCount: number, itemSize: Size, list
// check if it's correct), we forcefully set it multiple times over the next
// few milliseconds, hoping that maybe one of these attempts will stick.
//
- // This is most likely a race condition in either Chromimum or Electron
+ // This is most likely a race condition in either Chromium or Electron
// although I couldn't find an upstream issue.
//
// Setting the value only once after a short time, for example 10ms, helps
diff --git a/packages/app-desktop/gui/NoteListItem.tsx b/packages/app-desktop/gui/NoteListItem.tsx
index 05003d577..9cf78479d 100644
--- a/packages/app-desktop/gui/NoteListItem.tsx
+++ b/packages/app-desktop/gui/NoteListItem.tsx
@@ -138,7 +138,7 @@ function NoteListItem(props: NoteListItemProps, ref: any) {
if (error.name !== 'SyntaxError') {
throw error;
}
- // An error of 'Regular expression too large' might occour in the markJs library
+ // An error of 'Regular expression too large' might occur in the markJs library
// when the input is really big, this catch is here to avoid the application crashing
// https://github.com/laurent22/joplin/issues/7634
console.error('Error while trying to highlight words from search: ', error);
diff --git a/packages/app-desktop/gui/NoteListItem/utils/getNoteTitleHtml.ts b/packages/app-desktop/gui/NoteListItem/utils/getNoteTitleHtml.ts
index fe38c5e89..39e20d4db 100644
--- a/packages/app-desktop/gui/NoteListItem/utils/getNoteTitleHtml.ts
+++ b/packages/app-desktop/gui/NoteListItem/utils/getNoteTitleHtml.ts
@@ -25,7 +25,7 @@ const getNoteTitleHtml = (highlightedWords: string[], displayTitle: string) => {
if (error.name !== 'SyntaxError') {
throw error;
}
- // An error of 'Regular expression too large' might occour in the markJs library
+ // An error of 'Regular expression too large' might occur in the markJs library
// when the input is really big, this catch is here to avoid the application crashing
// https://github.com/laurent22/joplin/issues/7634
// console.error('Error while trying to highlight words from search: ', error);
diff --git a/packages/app-desktop/gui/NoteRevisionViewer.tsx b/packages/app-desktop/gui/NoteRevisionViewer.tsx
index 47e5b7f21..e4a827686 100644
--- a/packages/app-desktop/gui/NoteRevisionViewer.tsx
+++ b/packages/app-desktop/gui/NoteRevisionViewer.tsx
@@ -155,7 +155,7 @@ class NoteRevisionViewerComponent extends React.PureComponent {
}
private async webview_ipcMessage(event: any) {
- // For the revision view, we only suppport a minimal subset of the IPC messages.
+ // For the revision view, we only support a minimal subset of the IPC messages.
// For example, we don't need interactive checkboxes or sync between viewer and editor view.
// We try to get most links work though, except for internal (joplin://) links.
diff --git a/packages/app-desktop/gui/PromptDialog.tsx b/packages/app-desktop/gui/PromptDialog.tsx
index 26ff02d3c..e28bdf2d4 100644
--- a/packages/app-desktop/gui/PromptDialog.tsx
+++ b/packages/app-desktop/gui/PromptDialog.tsx
@@ -245,7 +245,7 @@ export default class PromptDialog extends React.Component {
const onKeyDown = (event: any) => {
if (event.key === 'Enter') {
// If the dropdown is open, we don't close the dialog - instead
- // the currently item will be selcted. If it is closed however
+ // the currently item will be selected. If it is closed however
// we confirm the dialog.
if ((this.props.inputType === 'tags' || this.props.inputType === 'dropdown') && this.menuIsOpened_) {
// Do nothing
diff --git a/packages/app-desktop/gui/ResizableLayout/utils/useLayoutItemSizes.ts b/packages/app-desktop/gui/ResizableLayout/utils/useLayoutItemSizes.ts
index 9788c1708..f9c1b7abb 100644
--- a/packages/app-desktop/gui/ResizableLayout/utils/useLayoutItemSizes.ts
+++ b/packages/app-desktop/gui/ResizableLayout/utils/useLayoutItemSizes.ts
@@ -11,7 +11,7 @@ export interface LayoutItemSizes {
}
// Container always take the full space while the items within it need to
-// accomodate for the resize handle.
+// accommodate for the resize handle.
export function itemSize(item: LayoutItem, parent: LayoutItem | null, sizes: LayoutItemSizes, isContainer: boolean): Size {
const parentResizableRight = !!parent && parent.resizableRight;
const parentResizableBottom = !!parent && parent.resizableBottom;
diff --git a/packages/app-desktop/gui/ResizableLayout/utils/validateLayout.ts b/packages/app-desktop/gui/ResizableLayout/utils/validateLayout.ts
index 16fbe2518..e56504060 100644
--- a/packages/app-desktop/gui/ResizableLayout/utils/validateLayout.ts
+++ b/packages/app-desktop/gui/ResizableLayout/utils/validateLayout.ts
@@ -89,7 +89,7 @@ function itemShouldBeVisible(item: LayoutItem): boolean {
}
// If all children of a container are hidden, the container should be
-// hidden too. A container visiblity cannot be changed by the user.
+// hidden too. A container visibility cannot be changed by the user.
function updateContainerVisibility(_itemIndex: number, itemDraft: LayoutItem, _parent: LayoutItem) {
if (itemDraft.children) {
itemDraft.visible = itemShouldBeVisible(itemDraft);
diff --git a/packages/app-desktop/gui/StatusScreen/StatusScreen.tsx b/packages/app-desktop/gui/StatusScreen/StatusScreen.tsx
index 4e9a1d3c4..4f95f3a14 100644
--- a/packages/app-desktop/gui/StatusScreen/StatusScreen.tsx
+++ b/packages/app-desktop/gui/StatusScreen/StatusScreen.tsx
@@ -41,14 +41,14 @@ async function exportDebugReportClick() {
function StatusScreen(props: Props) {
const [report, setReport] = useState([]);
- async function resfreshScreen() {
+ async function refreshScreen() {
const service = new ReportService();
const r = await service.status(Setting.value('sync.target'));
setReport(r);
}
useEffect(() => {
- void resfreshScreen();
+ void refreshScreen();
}, []);
const theme = themeStyle(props.themeId);
@@ -86,7 +86,7 @@ function StatusScreen(props: Props) {
if (section.canRetryAll) {
items.push(renderSectionRetryAll(`${key}_${section.title}`, async () => {
await section.retryAllHandler();
- void resfreshScreen();
+ void refreshScreen();
}));
}
return items;
@@ -112,7 +112,7 @@ function StatusScreen(props: Props) {
if (item.canRetry) {
const onClick = async () => {
await item.retryHandler();
- void resfreshScreen();
+ void refreshScreen();
};
retryLink = (
diff --git a/packages/app-desktop/gui/StyleSheets/StyleSheetContainer.tsx b/packages/app-desktop/gui/StyleSheets/StyleSheetContainer.tsx
index 079c9cb30..462dc3145 100644
--- a/packages/app-desktop/gui/StyleSheets/StyleSheetContainer.tsx
+++ b/packages/app-desktop/gui/StyleSheets/StyleSheetContainer.tsx
@@ -5,7 +5,7 @@
// same effect.
//
// It's still reliable because the lifecyle of adding the CSS and removing on
-// unmout is handled properly. There should only be one such component on the
+// unmount is handled properly. There should only be one such component on the
// page.
import { useEffect, useState } from 'react';
diff --git a/packages/app-desktop/gui/note-viewer/index.html b/packages/app-desktop/gui/note-viewer/index.html
index 137177429..192b65b78 100644
--- a/packages/app-desktop/gui/note-viewer/index.html
+++ b/packages/app-desktop/gui/note-viewer/index.html
@@ -109,7 +109,7 @@
let ignoreNextScrollEventCount_ = 0;
// ignoreNextScrollEvent() provides a way to skip scroll events for a certain duration.
- // In general, it should be called whenever the scroll value is set explicitely (programmatically)
+ // In general, it should be called whenever the scroll value is set explicitly (programmatically)
// so as to differentiate scroll events generated by the user (when scrolling the view) and those
// generated by the application.
function ignoreNextScrollEvent() {
diff --git a/packages/app-desktop/package.json b/packages/app-desktop/package.json
index a5a3f168b..af4136447 100644
--- a/packages/app-desktop/package.json
+++ b/packages/app-desktop/package.json
@@ -1,6 +1,6 @@
{
"name": "@joplin/app-desktop",
- "version": "2.14.16",
+ "version": "2.14.17",
"description": "Joplin for Desktop",
"main": "main.js",
"private": true,
diff --git a/packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.ts b/packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.ts
index 006dda633..2e04da295 100644
--- a/packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.ts
+++ b/packages/app-desktop/services/sortOrder/notesSortOrderUtils.test.ts
@@ -15,7 +15,7 @@ describe('notesSortOrderUtils', () => {
expect(notesSortOrderFieldArray()).toStrictEqual(expected);
});
- it('should provide the next field cyclicly', async () => {
+ it('should provide the next field cyclically', async () => {
expect(notesSortOrderNextField('user_updated_time')).toBe('user_created_time');
expect(notesSortOrderNextField('order')).toBe('user_updated_time');
});
diff --git a/packages/app-desktop/services/sortOrder/notesSortOrderUtils.ts b/packages/app-desktop/services/sortOrder/notesSortOrderUtils.ts
index 482f5d7e2..139b954e2 100644
--- a/packages/app-desktop/services/sortOrder/notesSortOrderUtils.ts
+++ b/packages/app-desktop/services/sortOrder/notesSortOrderUtils.ts
@@ -22,7 +22,7 @@ export const notesSortOrderNextField = (currentField: string) => {
};
export const setNotesSortOrder = (field?: string, reverse?: boolean) => {
- // field: Sort order's field. undefined means changing a field cyclicly.
+ // field: Sort order's field. undefined means changing a field cyclically.
// reverse: whether the sort order is reversed or not. undefined means toggling.
let nextField = field;
let nextReverse = reverse;
diff --git a/packages/app-desktop/tools/copy7Zip.ts b/packages/app-desktop/tools/copy7Zip.ts
index 531dc01d7..e24f3ffbc 100644
--- a/packages/app-desktop/tools/copy7Zip.ts
+++ b/packages/app-desktop/tools/copy7Zip.ts
@@ -3,7 +3,7 @@ import { copy } from 'fs-extra';
import { dirname, join } from 'path';
const copy7Zip = async () => {
- // We allow buildin for a different architecture/platform with
+ // We allow building for a different architecture/platform with
// the npm_config_target_arch and npm_config_target_platform environment variables.
//
// These are the same environment variables used by yarn when downloading dependencies.
diff --git a/packages/app-desktop/utils/restartInSafeModeFromMain.test.ts b/packages/app-desktop/utils/restartInSafeModeFromMain.test.ts
index ebbb7aa28..20b7ecbea 100644
--- a/packages/app-desktop/utils/restartInSafeModeFromMain.test.ts
+++ b/packages/app-desktop/utils/restartInSafeModeFromMain.test.ts
@@ -15,7 +15,7 @@ jest.doMock('../bridge', () => ({
'--profile', currentProfileDirectory,
],
env: () => 'dev',
- appName: () => 'joplin-destkop',
+ appName: () => 'joplin-desktop',
}),
}));
diff --git a/packages/app-mobile/android/app/build.gradle b/packages/app-mobile/android/app/build.gradle
index c5ece0f7f..c7141c5c4 100644
--- a/packages/app-mobile/android/app/build.gradle
+++ b/packages/app-mobile/android/app/build.gradle
@@ -110,8 +110,8 @@ android {
applicationId "net.cozic.joplin"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
- versionCode 2097738
- versionName "2.14.8"
+ versionCode 2097739
+ versionName "2.14.9"
ndk {
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
diff --git a/packages/app-mobile/components/ExtendedWebView.tsx b/packages/app-mobile/components/ExtendedWebView.tsx
index c0ec25828..d9b2ba4d1 100644
--- a/packages/app-mobile/components/ExtendedWebView.tsx
+++ b/packages/app-mobile/components/ExtendedWebView.tsx
@@ -9,8 +9,6 @@ import { WebView, WebViewMessageEvent } from 'react-native-webview';
import { WebViewErrorEvent, WebViewEvent, WebViewSource } from 'react-native-webview/lib/WebViewTypes';
import Setting from '@joplin/lib/models/Setting';
-import { themeStyle } from '@joplin/lib/theme';
-import { Theme } from '@joplin/lib/themes/type';
import shim from '@joplin/lib/shim';
import { StyleProp, ViewStyle } from 'react-native';
@@ -34,8 +32,6 @@ type OnLoadEndCallback = (event: WebViewEvent)=> void;
type OnFileUpdateCallback = (event: SourceFileUpdateEvent)=> void;
interface Props {
- themeId: number;
-
// A name to be associated with the WebView (e.g. NoteEditor)
// This name should be unique.
webviewInstanceId: string;
@@ -67,7 +63,6 @@ interface Props {
}
const ExtendedWebView = (props: Props, ref: Ref) => {
- const theme: Theme = themeStyle(props.themeId);
const webviewRef = useRef(null);
const [source, setSource] = useState(undefined);
@@ -135,7 +130,10 @@ const ExtendedWebView = (props: Props, ref: Ref) => {
return (
void;
}
-const webViewStyle = {
- backgroundColor: 'transparent',
-};
-
export default function NoteBodyViewer(props: Props) {
const dialogBoxRef = useRef(null);
const webviewRef = useRef(null);
@@ -103,8 +99,6 @@ export default function NoteBodyViewer(props: Props) {
{
}
/* Hide the save/close icons on small screens. This isn't done in the upstream
- js-draw repository partially beause it isn't as well localized as Joplin
+ js-draw repository partially because it isn't as well localized as Joplin
(icons can be used to suggest the meaning of a button when a translation is
unavailable). */
.toolbar-edge-toolbar:not(.one-row) .toolwidget-tag--save .toolbar-icon,
@@ -314,7 +314,6 @@ const ImageEditor = (props: Props) => {
return (
{
const minDimen = 45;
diff --git a/packages/app-mobile/components/NoteEditor/NoteEditor.tsx b/packages/app-mobile/components/NoteEditor/NoteEditor.tsx
index 11e91bfab..c207db87c 100644
--- a/packages/app-mobile/components/NoteEditor/NoteEditor.tsx
+++ b/packages/app-mobile/components/NoteEditor/NoteEditor.tsx
@@ -92,7 +92,7 @@ function useHtml(css: string): string {
.cm-scroller {
overflow: none;
- /* Ensure that the editor can be foused by clicking on the lower half of the screen.
+ /* Ensure that the editor can be focused by clicking on the lower half of the screen.
Don't use 100vh to prevent a scrollbar being present for empty notes. */
min-height: 80vh;
}
@@ -488,7 +488,6 @@ function NoteEditor(props: Props, ref: any) {
}}>
{
control.setSearchState(newState);
};
- // Creates a TextInut with the given parameters
+ // Creates a TextInput with the given parameters
const createInput = (
placeholder: string, value: string, onChange: OnChangeCallback, autoFocus: boolean,
) => {
diff --git a/packages/app-mobile/components/app-nav.tsx b/packages/app-mobile/components/app-nav.tsx
index d55d49474..85ba4c8d8 100644
--- a/packages/app-mobile/components/app-nav.tsx
+++ b/packages/app-mobile/components/app-nav.tsx
@@ -64,7 +64,7 @@ class AppNavComponent extends Component {
private keyboardWillChangeFrame = (evt: KeyboardEvent) => {
const windowWidth = Dimensions.get('window').width;
- // If the keyboard isn't as wide as the window, the floating keyboard is diabled.
+ // If the keyboard isn't as wide as the window, the floating keyboard is disabled.
// See https://github.com/facebook/react-native/issues/29473#issuecomment-696658937
this.setState({
floatingKeyboardEnabled: evt.endCoordinates.width < windowWidth,
@@ -101,7 +101,7 @@ class AppNavComponent extends Component {
const style = { flex: 1, backgroundColor: theme.backgroundColor };
- // When the floating keybaord is enabled, the KeyboardAvoidingView can have a very small
+ // When the floating keyboard is enabled, the KeyboardAvoidingView can have a very small
// height. Don't use the KeyboardAvoidingView when the floating keyboard is enabled.
// See https://github.com/facebook/react-native/issues/29473
const keyboardAvoidingViewEnabled = !this.state.floatingKeyboardEnabled;
diff --git a/packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx b/packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx
index 925fa47c4..8b41257ef 100644
--- a/packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx
+++ b/packages/app-mobile/components/screens/ConfigScreen/ConfigScreen.tsx
@@ -80,7 +80,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
- // to ignore TLS erros we need to chage the global state of the app, if the check fails we need to restore the original state
+ // to ignore TLS errors we need to change the global state of the app, if the check fails we need to restore the original state
// this call sets the new value and returns the previous one which we can use later to revert the change
const prevIgnoreTlsErrors = await setIgnoreTlsErrors(this.state.settings['net.ignoreTlsErrors']);
const result = await shared.checkSyncConfig(this, this.state.settings);
@@ -257,7 +257,7 @@ class ConfigScreenComponent extends BaseScreenComponent => {
+ private handleNavigateToNewScreen = async (): Promise => {
await this.promptSaveChanges();
// Continue navigation
@@ -306,14 +306,14 @@ class ConfigScreenComponent extends BaseScreenComponent void, options: any = null) {
diff --git a/packages/app-mobile/components/screens/LogScreen.tsx b/packages/app-mobile/components/screens/LogScreen.tsx
index 9f97d410d..4788dd2e5 100644
--- a/packages/app-mobile/components/screens/LogScreen.tsx
+++ b/packages/app-mobile/components/screens/LogScreen.tsx
@@ -67,13 +67,13 @@ class LogScreenComponent extends BaseScreenComponent {
}
setTimeout(() => {
this.refreshLogTimeout = null;
- void this.resfreshLogEntries();
+ void this.refreshLogEntries();
}, 600);
}
}
public override componentDidMount() {
- void this.resfreshLogEntries();
+ void this.refreshLogEntries();
if (this.props.navigation.state.defaultFilter) {
this.setState({ filter: this.props.navigation.state.defaultFilter });
@@ -155,7 +155,7 @@ class LogScreenComponent extends BaseScreenComponent {
return levels;
}
- private async resfreshLogEntries(showErrorsOnly: boolean = null) {
+ private async refreshLogEntries(showErrorsOnly: boolean = null) {
if (showErrorsOnly === null) showErrorsOnly = this.state.showErrorsOnly;
const limit = 1000;
@@ -168,7 +168,7 @@ class LogScreenComponent extends BaseScreenComponent {
}
private toggleErrorsOnly() {
- void this.resfreshLogEntries(!this.state.showErrorsOnly);
+ void this.refreshLogEntries(!this.state.showErrorsOnly);
}
private formatLogEntry(item: any) {
@@ -224,7 +224,7 @@ class LogScreenComponent extends BaseScreenComponent {