mirror of
https://github.com/laurent22/joplin.git
synced 2024-11-27 08:21:03 +02:00
Chore: Implement cSpell to detect spelling mistakes in codebase (#10001)
Co-authored-by: Helmut K. C. Tessarek <tessarek@evermeet.cx> Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
This commit is contained in:
parent
69cbd45782
commit
47f95cb294
198
cspell.json
198
cspell.json
@ -5,13 +5,19 @@
|
|||||||
"**/*.min.*",
|
"**/*.min.*",
|
||||||
"**/*.svg",
|
"**/*.svg",
|
||||||
"/_mydocs",
|
"/_mydocs",
|
||||||
|
"**/*.d.ts",
|
||||||
"/_releases",
|
"/_releases",
|
||||||
"/.git",
|
"/.git",
|
||||||
"/.yarn",
|
"/.yarn",
|
||||||
"/Assets",
|
"/Assets",
|
||||||
|
"cspell.json",
|
||||||
"/packages/app-cli/app/fuzzing.js",
|
"/packages/app-cli/app/fuzzing.js",
|
||||||
"/packages/app-cli/build",
|
"/packages/app-cli/build",
|
||||||
|
"/packages/generator-joplin/generators/app/templates/api/",
|
||||||
|
"/packages/app-cli/tests/enex_to_md/",
|
||||||
|
"/packages/app-cli/tests/html_to_md/",
|
||||||
"/packages/app-cli/tests/support",
|
"/packages/app-cli/tests/support",
|
||||||
|
"/packages/app-cli/tests/sync",
|
||||||
"/packages/app-cli/tests/test data",
|
"/packages/app-cli/tests/test data",
|
||||||
"/packages/app-cli/tests/tmp",
|
"/packages/app-cli/tests/tmp",
|
||||||
"/packages/app-clipper/content_scripts/JSDOMParser.js",
|
"/packages/app-clipper/content_scripts/JSDOMParser.js",
|
||||||
@ -20,16 +26,25 @@
|
|||||||
"/packages/app-clipper/popup/build/js/0.chunk.js",
|
"/packages/app-clipper/popup/build/js/0.chunk.js",
|
||||||
"/packages/app-clipper/popup/build/js/bundle.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/build/js/main.chunk.js",
|
|
||||||
"/packages/app-clipper/popup/config",
|
"/packages/app-clipper/popup/config",
|
||||||
|
"/packages/app-desktop/build/",
|
||||||
"/packages/app-desktop/vendor/",
|
"/packages/app-desktop/vendor/",
|
||||||
|
"/packages/app-mobile/lib/rnInjectedJs",
|
||||||
"/packages/app-mobile/pluginAssets",
|
"/packages/app-mobile/pluginAssets",
|
||||||
|
"/packages/doc-builder/build",
|
||||||
|
"/packages/doc-builder/i18n/",
|
||||||
"/packages/fork-sax/examples",
|
"/packages/fork-sax/examples",
|
||||||
"/packages/fork-sax/lib/sax.js",
|
"/packages/fork-sax/lib/sax.js",
|
||||||
|
"/packages/app-mobile/ios/Pods/",
|
||||||
|
"/packages/renderer/highlight.ts",
|
||||||
"/packages/fork-sax/test",
|
"/packages/fork-sax/test",
|
||||||
|
"/packages/app-mobile/utils/fs-driver/runOnDeviceTests.ts",
|
||||||
"/packages/fork-uslug",
|
"/packages/fork-uslug",
|
||||||
|
"/packages/default-plugins/plugin-sources/",
|
||||||
|
"/packages/app-desktop/utils/checkForUpdatesUtilsTestData.ts",
|
||||||
"/packages/lib/locales",
|
"/packages/lib/locales",
|
||||||
"/packages/lib/mime-utils-types.js",
|
"/packages/lib/mime-utils-types.js",
|
||||||
|
"/packages/server/src/utils/testing/randomWords.ts",
|
||||||
"/packages/lib/parameters.js",
|
"/packages/lib/parameters.js",
|
||||||
"/packages/lib/plugin_types",
|
"/packages/lib/plugin_types",
|
||||||
"/packages/lib/resourceUtils.js",
|
"/packages/lib/resourceUtils.js",
|
||||||
@ -38,6 +53,8 @@
|
|||||||
"/packages/lib/welcomeAssets.js",
|
"/packages/lib/welcomeAssets.js",
|
||||||
"/packages/turndown-plugin-gfm/config",
|
"/packages/turndown-plugin-gfm/config",
|
||||||
"/packages/turndown/config",
|
"/packages/turndown/config",
|
||||||
|
"/readme/_i18n",
|
||||||
|
"/readme/i18n",
|
||||||
"node_modules"
|
"node_modules"
|
||||||
],
|
],
|
||||||
"words": [
|
"words": [
|
||||||
@ -63,13 +80,16 @@
|
|||||||
"ambrt",
|
"ambrt",
|
||||||
"Amharic",
|
"Amharic",
|
||||||
"amothc",
|
"amothc",
|
||||||
|
"anchorpage",
|
||||||
"andrejilderda",
|
"andrejilderda",
|
||||||
"anki",
|
"anki",
|
||||||
|
"annotatescrollbar",
|
||||||
"Antarctique",
|
"Antarctique",
|
||||||
"antarctiques",
|
"antarctiques",
|
||||||
"Antártico",
|
"Antártico",
|
||||||
"anymore",
|
"anymore",
|
||||||
"apidoc",
|
"apidoc",
|
||||||
|
"apos",
|
||||||
"appiconset",
|
"appiconset",
|
||||||
"applewebkit",
|
"applewebkit",
|
||||||
"approot",
|
"approot",
|
||||||
@ -77,23 +97,36 @@
|
|||||||
"Aragonés",
|
"Aragonés",
|
||||||
"ARITIM",
|
"ARITIM",
|
||||||
"armeabi",
|
"armeabi",
|
||||||
|
"asdfasf",
|
||||||
"asterix",
|
"asterix",
|
||||||
"atest",
|
"atest",
|
||||||
"atestb",
|
"atestb",
|
||||||
|
"atleast",
|
||||||
"attribname",
|
"attribname",
|
||||||
"attribvalue",
|
"attribvalue",
|
||||||
"authcode",
|
"authcode",
|
||||||
"autocompleteitem",
|
"autocompleteitem",
|
||||||
"autocompleter",
|
"autocompleter",
|
||||||
"Autocompleter",
|
"Autocompleter",
|
||||||
|
"autocompletions",
|
||||||
"AUTOEXEC",
|
"AUTOEXEC",
|
||||||
"autohide",
|
"autohide",
|
||||||
|
"Persistable",
|
||||||
|
"centered",
|
||||||
|
"invlaid",
|
||||||
|
"automatch",
|
||||||
|
"autoresize",
|
||||||
|
"Autoresize",
|
||||||
"Avenir",
|
"Avenir",
|
||||||
|
"avif",
|
||||||
|
"awaiter",
|
||||||
"Ayiti",
|
"Ayiti",
|
||||||
"azamah",
|
"azamah",
|
||||||
"Azərbaycan",
|
"Azərbaycan",
|
||||||
"backoff",
|
"backoff",
|
||||||
"Bangla",
|
"Bangla",
|
||||||
|
"bbox",
|
||||||
|
"Bbox",
|
||||||
"Bêafrîka",
|
"Bêafrîka",
|
||||||
"beforeinput",
|
"beforeinput",
|
||||||
"België",
|
"België",
|
||||||
@ -106,10 +139,14 @@
|
|||||||
"Bislama",
|
"Bislama",
|
||||||
"blabla",
|
"blabla",
|
||||||
"blablablabla",
|
"blablablabla",
|
||||||
|
"blockid",
|
||||||
|
"bonjour",
|
||||||
|
"Bonjour",
|
||||||
"boohay",
|
"boohay",
|
||||||
"Bosna",
|
"Bosna",
|
||||||
"Bouvet",
|
"Bouvet",
|
||||||
"Bouvetøya",
|
"Bouvetøya",
|
||||||
|
"Bpcy",
|
||||||
"browserslist",
|
"browserslist",
|
||||||
"bthqu",
|
"bthqu",
|
||||||
"btns",
|
"btns",
|
||||||
@ -136,26 +173,35 @@
|
|||||||
"cdatastart",
|
"cdatastart",
|
||||||
"cdot",
|
"cdot",
|
||||||
"ceaf",
|
"ceaf",
|
||||||
|
"ceea",
|
||||||
"centrafricaine",
|
"centrafricaine",
|
||||||
"Centrafrican",
|
"Centrafrican",
|
||||||
"Česká",
|
"Česká",
|
||||||
"changedtitle",
|
"changedtitle",
|
||||||
|
"Charcode",
|
||||||
"charcodes",
|
"charcodes",
|
||||||
"checkboxclick",
|
"checkboxclick",
|
||||||
"checkmark",
|
"checkmark",
|
||||||
"chemfive",
|
"chemfive",
|
||||||
|
"childs",
|
||||||
"choiceitem",
|
"choiceitem",
|
||||||
"chromedriver",
|
"chromedriver",
|
||||||
"chromeframe",
|
"chromeframe",
|
||||||
"chromeos",
|
"chromeos",
|
||||||
"Città",
|
"Città",
|
||||||
|
"Clearable",
|
||||||
|
"closebrackets",
|
||||||
"Cmds",
|
"Cmds",
|
||||||
|
"codemirror",
|
||||||
"codepoint",
|
"codepoint",
|
||||||
|
"codesample",
|
||||||
|
"Colorful",
|
||||||
"colorinput",
|
"colorinput",
|
||||||
"colorpicker",
|
"colorpicker",
|
||||||
"colorswatch",
|
"colorswatch",
|
||||||
"colspan",
|
"colspan",
|
||||||
"committerdate",
|
"committerdate",
|
||||||
|
"commmand",
|
||||||
"commmmmand",
|
"commmmmand",
|
||||||
"commonmark",
|
"commonmark",
|
||||||
"COMMONMARK",
|
"COMMONMARK",
|
||||||
@ -164,6 +210,7 @@
|
|||||||
"compositionstart",
|
"compositionstart",
|
||||||
"compositionupdate",
|
"compositionupdate",
|
||||||
"conflicter",
|
"conflicter",
|
||||||
|
"connectionstring",
|
||||||
"contenteditable",
|
"contenteditable",
|
||||||
"contextform",
|
"contextform",
|
||||||
"contextformbutton",
|
"contextformbutton",
|
||||||
@ -194,12 +241,15 @@
|
|||||||
"dataimg",
|
"dataimg",
|
||||||
"datauri",
|
"datauri",
|
||||||
"Datauri",
|
"Datauri",
|
||||||
|
"dataurl",
|
||||||
"datetime",
|
"datetime",
|
||||||
"Datetime",
|
"Datetime",
|
||||||
"davris",
|
"davris",
|
||||||
"dbuuid",
|
"dbuuid",
|
||||||
"DDTHH",
|
"DDTHH",
|
||||||
|
"deaccelerates",
|
||||||
"deflist",
|
"deflist",
|
||||||
|
"deindent",
|
||||||
"deinit",
|
"deinit",
|
||||||
"Démocratique",
|
"Démocratique",
|
||||||
"deselector",
|
"deselector",
|
||||||
@ -209,11 +259,15 @@
|
|||||||
"dialogs",
|
"dialogs",
|
||||||
"Dialogs",
|
"Dialogs",
|
||||||
"DIALOGS",
|
"DIALOGS",
|
||||||
|
"Dimen",
|
||||||
|
"Dismisable",
|
||||||
"Distill",
|
"Distill",
|
||||||
"dists",
|
"dists",
|
||||||
|
"Divs",
|
||||||
"docid",
|
"docid",
|
||||||
"docsize",
|
"docsize",
|
||||||
"doctypes",
|
"doctypes",
|
||||||
|
"docu",
|
||||||
"doesnotwork",
|
"doesnotwork",
|
||||||
"doesntexist",
|
"doesntexist",
|
||||||
"doesntlookright",
|
"doesntlookright",
|
||||||
@ -223,9 +277,12 @@
|
|||||||
"domutils",
|
"domutils",
|
||||||
"DONATELINKS",
|
"DONATELINKS",
|
||||||
"downarrow",
|
"downarrow",
|
||||||
|
"dragcursor",
|
||||||
"dragdrop",
|
"dragdrop",
|
||||||
"draggesture",
|
"draggesture",
|
||||||
|
"dropdownalert",
|
||||||
"dünn",
|
"dünn",
|
||||||
|
"Dups",
|
||||||
"dylib",
|
"dylib",
|
||||||
"dynamiclib",
|
"dynamiclib",
|
||||||
"ecuatorial",
|
"ecuatorial",
|
||||||
@ -241,13 +298,16 @@
|
|||||||
"elems",
|
"elems",
|
||||||
"ellipsize",
|
"ellipsize",
|
||||||
"ELOCKED",
|
"ELOCKED",
|
||||||
|
"emptylist",
|
||||||
"encryptable",
|
"encryptable",
|
||||||
"endregion",
|
"endregion",
|
||||||
"enex",
|
"enex",
|
||||||
"Enex",
|
"Enex",
|
||||||
"ENEX",
|
"ENEX",
|
||||||
|
"ENSCOCOAERRORDOMAIN",
|
||||||
"enumber",
|
"enumber",
|
||||||
"eqeqeq",
|
"eqeqeq",
|
||||||
|
"eqnsw",
|
||||||
"équatoriale",
|
"équatoriale",
|
||||||
"Erro",
|
"Erro",
|
||||||
"errorish",
|
"errorish",
|
||||||
@ -269,21 +329,34 @@
|
|||||||
"Fahrräder",
|
"Fahrräder",
|
||||||
"FAILSAFE",
|
"FAILSAFE",
|
||||||
"fallbacks",
|
"fallbacks",
|
||||||
|
"falsey",
|
||||||
"fancymenuitem",
|
"fancymenuitem",
|
||||||
"fancytype",
|
"fancytype",
|
||||||
"favorites",
|
"favorites",
|
||||||
|
"fhash",
|
||||||
"Fiber",
|
"Fiber",
|
||||||
"filepicker",
|
"filepicker",
|
||||||
|
"Flavored",
|
||||||
|
"flusing",
|
||||||
|
"foldericon",
|
||||||
"folderid",
|
"folderid",
|
||||||
|
"folderkey",
|
||||||
|
"foldertest",
|
||||||
"foldl",
|
"foldl",
|
||||||
"fontawesome",
|
"fontawesome",
|
||||||
"fontface",
|
"fontface",
|
||||||
|
"foobar",
|
||||||
|
"Foobar",
|
||||||
"forall",
|
"forall",
|
||||||
"forcewake",
|
"forcewake",
|
||||||
|
"forecolor",
|
||||||
|
"formatcoords",
|
||||||
"Føroyar",
|
"Føroyar",
|
||||||
"fortawesome",
|
"fortawesome",
|
||||||
"française",
|
"française",
|
||||||
"françaises",
|
"françaises",
|
||||||
|
"FULLNAME",
|
||||||
|
"Fullpath",
|
||||||
"Gabuutih",
|
"Gabuutih",
|
||||||
"gedit",
|
"gedit",
|
||||||
"geoip",
|
"geoip",
|
||||||
@ -292,6 +365,7 @@
|
|||||||
"geoplugin",
|
"geoplugin",
|
||||||
"getlastmodified",
|
"getlastmodified",
|
||||||
"gettext",
|
"gettext",
|
||||||
|
"Ghpcy",
|
||||||
"githubusercontent",
|
"githubusercontent",
|
||||||
"Gora",
|
"Gora",
|
||||||
"gotchas",
|
"gotchas",
|
||||||
@ -313,16 +387,22 @@
|
|||||||
"Haïti",
|
"Haïti",
|
||||||
"hanlder",
|
"hanlder",
|
||||||
"Hausa",
|
"Hausa",
|
||||||
|
"hdpi",
|
||||||
"headerless",
|
"headerless",
|
||||||
|
"Heino",
|
||||||
"Heisenbug",
|
"Heisenbug",
|
||||||
|
"héllô",
|
||||||
"Hercegovina",
|
"Hercegovina",
|
||||||
|
"hideothers",
|
||||||
"hift",
|
"hift",
|
||||||
"highjack",
|
"highjack",
|
||||||
"highlited",
|
"highlited",
|
||||||
"historyhas",
|
"historyhas",
|
||||||
"HMRKG",
|
"HMRKG",
|
||||||
|
"hocr",
|
||||||
"hoge",
|
"hoge",
|
||||||
"homenote",
|
"homenote",
|
||||||
|
"horiz",
|
||||||
"hotfolder",
|
"hotfolder",
|
||||||
"Howver",
|
"Howver",
|
||||||
"hpagent",
|
"hpagent",
|
||||||
@ -335,6 +415,7 @@
|
|||||||
"icns",
|
"icns",
|
||||||
"iconset",
|
"iconset",
|
||||||
"iconutil",
|
"iconutil",
|
||||||
|
"ified",
|
||||||
"Iforgot",
|
"Iforgot",
|
||||||
"iframes",
|
"iframes",
|
||||||
"ihack",
|
"ihack",
|
||||||
@ -342,6 +423,7 @@
|
|||||||
"iìíîïī",
|
"iìíîïī",
|
||||||
"IÌÍÎÏĪ",
|
"IÌÍÎÏĪ",
|
||||||
"ijkl",
|
"ijkl",
|
||||||
|
"imageeditor",
|
||||||
"imagelink",
|
"imagelink",
|
||||||
"imagetools",
|
"imagetools",
|
||||||
"immer",
|
"immer",
|
||||||
@ -372,21 +454,27 @@
|
|||||||
"itunes",
|
"itunes",
|
||||||
"Jabuuti",
|
"Jabuuti",
|
||||||
"jackgruber",
|
"jackgruber",
|
||||||
|
"jianguoyun",
|
||||||
"joeattardi",
|
"joeattardi",
|
||||||
"jopext",
|
"jopext",
|
||||||
"joplinapp",
|
"joplinapp",
|
||||||
"JOPLINAPP",
|
"JOPLINAPP",
|
||||||
|
"joplinbot",
|
||||||
"joplincloud",
|
"joplincloud",
|
||||||
"joplindev",
|
"joplindev",
|
||||||
"JOPLINMOD",
|
"JOPLINMOD",
|
||||||
"joplintest",
|
"joplintest",
|
||||||
|
"joplinusercontent",
|
||||||
"jsbundles",
|
"jsbundles",
|
||||||
|
"jsdraw",
|
||||||
|
"Jsons",
|
||||||
"justtesting",
|
"justtesting",
|
||||||
"Kalaallit",
|
"Kalaallit",
|
||||||
"kalba",
|
"kalba",
|
||||||
"kanban",
|
"kanban",
|
||||||
"Kashmiri",
|
"Kashmiri",
|
||||||
"katex",
|
"katex",
|
||||||
|
"keybind",
|
||||||
"keychain",
|
"keychain",
|
||||||
"keycodes",
|
"keycodes",
|
||||||
"keymaps",
|
"keymaps",
|
||||||
@ -396,12 +484,15 @@
|
|||||||
"Kirundi",
|
"Kirundi",
|
||||||
"Ködörösêse",
|
"Ködörösêse",
|
||||||
"Komori",
|
"Komori",
|
||||||
|
"Kopiuj",
|
||||||
"Kpck",
|
"Kpck",
|
||||||
"Kūki",
|
"Kūki",
|
||||||
"Laothian",
|
"Laothian",
|
||||||
"lastmod",
|
"lastmod",
|
||||||
|
"Latviešu",
|
||||||
"Latvija",
|
"Latvija",
|
||||||
"lcov",
|
"lcov",
|
||||||
|
"ldapts",
|
||||||
"leaft",
|
"leaft",
|
||||||
"leftarrow",
|
"leftarrow",
|
||||||
"leftequilibrium",
|
"leftequilibrium",
|
||||||
@ -409,13 +500,17 @@
|
|||||||
"Lettish",
|
"Lettish",
|
||||||
"Lëtzebuerg",
|
"Lëtzebuerg",
|
||||||
"Levithan",
|
"Levithan",
|
||||||
|
"lezer",
|
||||||
"Liban",
|
"Liban",
|
||||||
|
"Libérez",
|
||||||
"libz",
|
"libz",
|
||||||
"Lietuva",
|
"Lietuva",
|
||||||
"Lietuvių",
|
"Lietuvių",
|
||||||
|
"lifecyle",
|
||||||
"lineheight",
|
"lineheight",
|
||||||
"Lingala",
|
"Lingala",
|
||||||
"linkg",
|
"linkg",
|
||||||
|
"linki",
|
||||||
"linkurl",
|
"linkurl",
|
||||||
"listbox",
|
"listbox",
|
||||||
"listfile",
|
"listfile",
|
||||||
@ -425,16 +520,20 @@
|
|||||||
"longpress",
|
"longpress",
|
||||||
"longpresscancel",
|
"longpresscancel",
|
||||||
"looooooong",
|
"looooooong",
|
||||||
|
"LSTM",
|
||||||
"ltrim",
|
"ltrim",
|
||||||
"Luxemburg",
|
"Luxemburg",
|
||||||
"Maarten",
|
"Maarten",
|
||||||
|
"macosm",
|
||||||
"Madagasikara",
|
"Madagasikara",
|
||||||
"Magyarország",
|
"Magyarország",
|
||||||
"majax",
|
"majax",
|
||||||
|
"managebutton",
|
||||||
"Mardown",
|
"Mardown",
|
||||||
"markdowncalc",
|
"markdowncalc",
|
||||||
"Maroc",
|
"Maroc",
|
||||||
"MASTERKEY",
|
"MASTERKEY",
|
||||||
|
"matchesonscrollbar",
|
||||||
"matchinfo",
|
"matchinfo",
|
||||||
"mathchoice",
|
"mathchoice",
|
||||||
"mathjax",
|
"mathjax",
|
||||||
@ -449,10 +548,12 @@
|
|||||||
"Mayen",
|
"Mayen",
|
||||||
"mchem",
|
"mchem",
|
||||||
"mechanim",
|
"mechanim",
|
||||||
|
"MEDIUMINT",
|
||||||
"mediumtext",
|
"mediumtext",
|
||||||
"menubutton",
|
"menubutton",
|
||||||
"mergeff",
|
"mergeff",
|
||||||
"Metadatas",
|
"Metadatas",
|
||||||
|
"Metadatum",
|
||||||
"México",
|
"México",
|
||||||
"mhchem",
|
"mhchem",
|
||||||
"middlewares",
|
"middlewares",
|
||||||
@ -463,9 +564,11 @@
|
|||||||
"mknote",
|
"mknote",
|
||||||
"mktodo",
|
"mktodo",
|
||||||
"MMYY",
|
"MMYY",
|
||||||
|
"mnop",
|
||||||
"modifié",
|
"modifié",
|
||||||
"monokai",
|
"monokai",
|
||||||
"MONOSPACE",
|
"MONOSPACE",
|
||||||
|
"mscz",
|
||||||
"msgctxt",
|
"msgctxt",
|
||||||
"msgfmt",
|
"msgfmt",
|
||||||
"msgmerge",
|
"msgmerge",
|
||||||
@ -494,7 +597,9 @@
|
|||||||
"nanoid",
|
"nanoid",
|
||||||
"Neaus",
|
"Neaus",
|
||||||
"Nederlands",
|
"Nederlands",
|
||||||
|
"needpassword",
|
||||||
"nestedmenuitem",
|
"nestedmenuitem",
|
||||||
|
"netinfo",
|
||||||
"newone",
|
"newone",
|
||||||
"Nextcloud",
|
"Nextcloud",
|
||||||
"njstrace",
|
"njstrace",
|
||||||
@ -506,13 +611,18 @@
|
|||||||
"noexpand",
|
"noexpand",
|
||||||
"nojs",
|
"nojs",
|
||||||
"nolongershared",
|
"nolongershared",
|
||||||
|
"noneditable",
|
||||||
"nonlatin",
|
"nonlatin",
|
||||||
"NONLATIN",
|
"NONLATIN",
|
||||||
"Noreg",
|
"Noreg",
|
||||||
"Norge",
|
"Norge",
|
||||||
"nospecialcharacters",
|
"nospecialcharacters",
|
||||||
|
"notaduration",
|
||||||
"notanumber",
|
"notanumber",
|
||||||
"notarization",
|
"notarization",
|
||||||
|
"notarytool",
|
||||||
|
"notesnook",
|
||||||
|
"Notesnook",
|
||||||
"notetags",
|
"notetags",
|
||||||
"Notif",
|
"Notif",
|
||||||
"notindexed",
|
"notindexed",
|
||||||
@ -520,9 +630,12 @@
|
|||||||
"nounce",
|
"nounce",
|
||||||
"Nounce",
|
"Nounce",
|
||||||
"Nounces",
|
"Nounces",
|
||||||
|
"nplurals",
|
||||||
"npmignore",
|
"npmignore",
|
||||||
|
"npmpackagejsonlintrc",
|
||||||
"numadd",
|
"numadd",
|
||||||
"numbersareok",
|
"numbersareok",
|
||||||
|
"reconsume",
|
||||||
"numdec",
|
"numdec",
|
||||||
"numdiv",
|
"numdiv",
|
||||||
"numlist",
|
"numlist",
|
||||||
@ -548,6 +661,7 @@
|
|||||||
"ondeclaration",
|
"ondeclaration",
|
||||||
"onedrive",
|
"onedrive",
|
||||||
"onelink",
|
"onelink",
|
||||||
|
"onfoo",
|
||||||
"onformat",
|
"onformat",
|
||||||
"onmatch",
|
"onmatch",
|
||||||
"onopentag",
|
"onopentag",
|
||||||
@ -557,6 +671,7 @@
|
|||||||
"onprocessinginstruction",
|
"onprocessinginstruction",
|
||||||
"onselfclosingtag",
|
"onselfclosingtag",
|
||||||
"ontext",
|
"ontext",
|
||||||
|
"ontouch",
|
||||||
"oòóôõöøō",
|
"oòóôõöøō",
|
||||||
"OÒÓÔÕÖØŌ",
|
"OÒÓÔÕÖØŌ",
|
||||||
"opentag",
|
"opentag",
|
||||||
@ -570,12 +685,17 @@
|
|||||||
"overidding",
|
"overidding",
|
||||||
"overriden",
|
"overriden",
|
||||||
"padd",
|
"padd",
|
||||||
|
"PAGEDOWN",
|
||||||
|
"PAGEUP",
|
||||||
"pandoc",
|
"pandoc",
|
||||||
"paperclip",
|
"paperclip",
|
||||||
|
"partageable",
|
||||||
|
"partageables",
|
||||||
"passthrough",
|
"passthrough",
|
||||||
"Päth",
|
"Päth",
|
||||||
"Pbuild",
|
"Pbuild",
|
||||||
"pbxproj",
|
"pbxproj",
|
||||||
|
"pcloud",
|
||||||
"pcmag",
|
"pcmag",
|
||||||
"pcnalx",
|
"pcnalx",
|
||||||
"pddv",
|
"pddv",
|
||||||
@ -584,6 +704,7 @@
|
|||||||
"père",
|
"père",
|
||||||
"Perú",
|
"Perú",
|
||||||
"pfff",
|
"pfff",
|
||||||
|
"pgdg",
|
||||||
"PGPASSWORD",
|
"PGPASSWORD",
|
||||||
"pidfile",
|
"pidfile",
|
||||||
"PLUGINLEGACY",
|
"PLUGINLEGACY",
|
||||||
@ -591,7 +712,13 @@
|
|||||||
"Polska",
|
"Polska",
|
||||||
"Polski",
|
"Polski",
|
||||||
"Polynésie",
|
"Polynésie",
|
||||||
|
"popover",
|
||||||
|
"Popover",
|
||||||
|
"popperjs",
|
||||||
"Português",
|
"Português",
|
||||||
|
"positionals",
|
||||||
|
"Postprocess",
|
||||||
|
"postprocessing",
|
||||||
"Potoczny's",
|
"Potoczny's",
|
||||||
"powerpoint",
|
"powerpoint",
|
||||||
"Prakash",
|
"Prakash",
|
||||||
@ -601,6 +728,7 @@
|
|||||||
"prerelease",
|
"prerelease",
|
||||||
"Prerelease",
|
"Prerelease",
|
||||||
"presigner",
|
"presigner",
|
||||||
|
"Pressable",
|
||||||
"prettycron",
|
"prettycron",
|
||||||
"pricetag",
|
"pricetag",
|
||||||
"Príncipe",
|
"Príncipe",
|
||||||
@ -627,18 +755,27 @@
|
|||||||
"reencrypted",
|
"reencrypted",
|
||||||
"Reencrypting",
|
"Reencrypting",
|
||||||
"reencrypts",
|
"reencrypts",
|
||||||
|
"Reformatter",
|
||||||
"regexes",
|
"regexes",
|
||||||
"Regexs",
|
"Regexs",
|
||||||
"Relavent",
|
"Relavent",
|
||||||
"relayouted",
|
"relayouted",
|
||||||
"rels",
|
"rels",
|
||||||
"renamings",
|
"renamings",
|
||||||
|
"Renderable",
|
||||||
"renderered",
|
"renderered",
|
||||||
"Renderered",
|
"Renderered",
|
||||||
|
"Replit's",
|
||||||
|
"replit",
|
||||||
|
"reponame",
|
||||||
"República",
|
"República",
|
||||||
"republika",
|
"republika",
|
||||||
"République",
|
"République",
|
||||||
"requestheaders",
|
"requestheaders",
|
||||||
|
"resourceid",
|
||||||
|
"resourceidhere",
|
||||||
|
"resourcekey",
|
||||||
|
"resourcetest",
|
||||||
"resourcetype",
|
"resourcetype",
|
||||||
"resynced",
|
"resynced",
|
||||||
"Rhaeto",
|
"Rhaeto",
|
||||||
@ -651,6 +788,7 @@
|
|||||||
"rmusin",
|
"rmusin",
|
||||||
"rnfs",
|
"rnfs",
|
||||||
"RNFS",
|
"RNFS",
|
||||||
|
"RNSAF",
|
||||||
"robocopy",
|
"robocopy",
|
||||||
"Roboto",
|
"Roboto",
|
||||||
"România",
|
"România",
|
||||||
@ -662,22 +800,33 @@
|
|||||||
"rseidelsohn",
|
"rseidelsohn",
|
||||||
"rtrim",
|
"rtrim",
|
||||||
"safeext",
|
"safeext",
|
||||||
|
"safemode",
|
||||||
|
"Safx",
|
||||||
"salut",
|
"salut",
|
||||||
"Sangho",
|
"Sangho",
|
||||||
"sasss",
|
"sasss",
|
||||||
|
"Sauvegardez",
|
||||||
"SAVEPOINT",
|
"SAVEPOINT",
|
||||||
"schtroumpf",
|
"schtroumpf",
|
||||||
"Schweiz",
|
"Schweiz",
|
||||||
|
"screenreader",
|
||||||
"Scrolllock",
|
"Scrolllock",
|
||||||
"scrollmap",
|
"scrollmap",
|
||||||
|
"scrollview",
|
||||||
|
"sdcard",
|
||||||
"seafdav",
|
"seafdav",
|
||||||
"Seafile",
|
"Seafile",
|
||||||
|
"searchbar",
|
||||||
|
"searchcursor",
|
||||||
"searchengine",
|
"searchengine",
|
||||||
"searchlimit",
|
"searchlimit",
|
||||||
"SEARCHOVERLAY",
|
"SEARCHOVERLAY",
|
||||||
|
"searchreplace",
|
||||||
"securerandom",
|
"securerandom",
|
||||||
"segdir",
|
"segdir",
|
||||||
|
"seiyab",
|
||||||
"selectbox",
|
"selectbox",
|
||||||
|
"selectedtext",
|
||||||
"Sénégal",
|
"Sénégal",
|
||||||
"Serializers",
|
"Serializers",
|
||||||
"setext",
|
"setext",
|
||||||
@ -688,12 +837,16 @@
|
|||||||
"Shoft",
|
"Shoft",
|
||||||
"shouldntendwithit",
|
"shouldntendwithit",
|
||||||
"shouldstartwiththis",
|
"shouldstartwiththis",
|
||||||
|
"showpasswordbutton",
|
||||||
"Shqip",
|
"Shqip",
|
||||||
"Shqipëria",
|
"Shqipëria",
|
||||||
"Sicen",
|
"Sicen",
|
||||||
|
"sidemenu",
|
||||||
|
"sidemenus",
|
||||||
"simplemath",
|
"simplemath",
|
||||||
"Siswati",
|
"Siswati",
|
||||||
"sizeinput",
|
"sizeinput",
|
||||||
|
"sizer",
|
||||||
"SJCL",
|
"SJCL",
|
||||||
"Slovenčina",
|
"Slovenčina",
|
||||||
"Slovenija",
|
"Slovenija",
|
||||||
@ -701,8 +854,13 @@
|
|||||||
"softbreaks",
|
"softbreaks",
|
||||||
"Solarised",
|
"Solarised",
|
||||||
"SOLARIZED",
|
"SOLARIZED",
|
||||||
|
"someclass",
|
||||||
"someid",
|
"someid",
|
||||||
|
"someidhere",
|
||||||
|
"someresourceid",
|
||||||
|
"somethingrandom",
|
||||||
"somewhereelse",
|
"somewhereelse",
|
||||||
|
"sourcecode",
|
||||||
"sourceurl",
|
"sourceurl",
|
||||||
"SPACEBAR",
|
"SPACEBAR",
|
||||||
"spaceno",
|
"spaceno",
|
||||||
@ -711,6 +869,7 @@
|
|||||||
"spellfix",
|
"spellfix",
|
||||||
"sphemy",
|
"sphemy",
|
||||||
"splitbutton",
|
"splitbutton",
|
||||||
|
"splitted",
|
||||||
"sprintf",
|
"sprintf",
|
||||||
"sqlts",
|
"sqlts",
|
||||||
"srcfolder",
|
"srcfolder",
|
||||||
@ -722,6 +881,7 @@
|
|||||||
"stex",
|
"stex",
|
||||||
"stilltryingtohack",
|
"stilltryingtohack",
|
||||||
"strack",
|
"strack",
|
||||||
|
"Strikethrough",
|
||||||
"Stringifiable",
|
"Stringifiable",
|
||||||
"subdir",
|
"subdir",
|
||||||
"subl",
|
"subl",
|
||||||
@ -741,9 +901,12 @@
|
|||||||
"taga",
|
"taga",
|
||||||
"tagb",
|
"tagb",
|
||||||
"tagc",
|
"tagc",
|
||||||
|
"tagkey",
|
||||||
|
"tagtest",
|
||||||
"Tajik",
|
"Tajik",
|
||||||
"takesover",
|
"takesover",
|
||||||
"targetfolder",
|
"targetfolder",
|
||||||
|
"tbtn",
|
||||||
"Tchad",
|
"Tchad",
|
||||||
"Teardown",
|
"Teardown",
|
||||||
"termi",
|
"termi",
|
||||||
@ -754,12 +917,15 @@
|
|||||||
"Testb",
|
"Testb",
|
||||||
"testcreate",
|
"testcreate",
|
||||||
"testexportfolder",
|
"testexportfolder",
|
||||||
|
"testid",
|
||||||
"testingconnection",
|
"testingconnection",
|
||||||
"testingkeychain",
|
"testingkeychain",
|
||||||
|
"testocr",
|
||||||
"testunit",
|
"testunit",
|
||||||
"texify",
|
"texify",
|
||||||
"Texify",
|
"Texify",
|
||||||
"textareas",
|
"textareas",
|
||||||
|
"Textcolor",
|
||||||
"textexportnote",
|
"textexportnote",
|
||||||
"textstyle",
|
"textstyle",
|
||||||
"thaaaaaaan",
|
"thaaaaaaan",
|
||||||
@ -772,16 +938,23 @@
|
|||||||
"Tiếng",
|
"Tiếng",
|
||||||
"Tigrinya",
|
"Tigrinya",
|
||||||
"tiiitlllle",
|
"tiiitlllle",
|
||||||
|
"TINYINT",
|
||||||
"tinymce",
|
"tinymce",
|
||||||
|
"tippy",
|
||||||
"titi",
|
"titi",
|
||||||
|
"titlecontent",
|
||||||
"titletitle",
|
"titletitle",
|
||||||
"tkwidget",
|
"tkwidget",
|
||||||
"tkwidgets",
|
"tkwidgets",
|
||||||
"Todos",
|
"Todos",
|
||||||
|
"toggleblock",
|
||||||
"togglebutton",
|
"togglebutton",
|
||||||
"togglemenuitem",
|
"togglemenuitem",
|
||||||
"toolip",
|
"toolip",
|
||||||
|
"toolwidget",
|
||||||
"tooshort",
|
"tooshort",
|
||||||
|
"Traduis",
|
||||||
|
"treshold",
|
||||||
"treymo",
|
"treymo",
|
||||||
"tripledash",
|
"tripledash",
|
||||||
"tsmerge",
|
"tsmerge",
|
||||||
@ -798,9 +971,12 @@
|
|||||||
"Typora",
|
"Typora",
|
||||||
"tzip",
|
"tzip",
|
||||||
"uastring",
|
"uastring",
|
||||||
|
"udostępnialne",
|
||||||
|
"udostępnialny",
|
||||||
"uglifycss",
|
"uglifycss",
|
||||||
"uglifyjs",
|
"uglifyjs",
|
||||||
"Uighur",
|
"Uighur",
|
||||||
|
"Uiid",
|
||||||
"unconflicted",
|
"unconflicted",
|
||||||
"underbrace",
|
"underbrace",
|
||||||
"Undos",
|
"Undos",
|
||||||
@ -808,12 +984,15 @@
|
|||||||
"unhighlighted",
|
"unhighlighted",
|
||||||
"unixlike",
|
"unixlike",
|
||||||
"unmocked",
|
"unmocked",
|
||||||
|
"Unnormalized",
|
||||||
|
"unoverriding",
|
||||||
"unserialize",
|
"unserialize",
|
||||||
"unserialized",
|
"unserialized",
|
||||||
"unserializes",
|
"unserializes",
|
||||||
"unserializing",
|
"unserializing",
|
||||||
"unshares",
|
"unshares",
|
||||||
"unsharing",
|
"unsharing",
|
||||||
|
"unspell",
|
||||||
"unusued",
|
"unusued",
|
||||||
"uparrow",
|
"uparrow",
|
||||||
"uphy",
|
"uphy",
|
||||||
@ -831,9 +1010,11 @@
|
|||||||
"UÙÚÛÜŮŪ",
|
"UÙÚÛÜŮŪ",
|
||||||
"valign",
|
"valign",
|
||||||
"Valign",
|
"Valign",
|
||||||
|
"valpha",
|
||||||
"vars",
|
"vars",
|
||||||
"Vars",
|
"Vars",
|
||||||
"Vaticano",
|
"Vaticano",
|
||||||
|
"vbscript",
|
||||||
"vers",
|
"vers",
|
||||||
"verylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongid",
|
"verylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongidverylongid",
|
||||||
"veryverylongclientidveryverylongclientidveryverylongclientidveryverylongclientid",
|
"veryverylongclientidveryverylongclientidveryverylongclientidveryverylongclientid",
|
||||||
@ -842,16 +1023,24 @@
|
|||||||
"viewbox",
|
"viewbox",
|
||||||
"Volapuk",
|
"Volapuk",
|
||||||
"Volívia",
|
"Volívia",
|
||||||
|
"vosk",
|
||||||
|
"Vosk",
|
||||||
"votearrow",
|
"votearrow",
|
||||||
|
"watchedicon",
|
||||||
"webclipper",
|
"webclipper",
|
||||||
"webdav",
|
"webdav",
|
||||||
"webfonts",
|
"webfonts",
|
||||||
|
"welc",
|
||||||
"whitespaces",
|
"whitespaces",
|
||||||
"widder",
|
"widder",
|
||||||
"Wifi",
|
"Wifi",
|
||||||
|
"Withéàö",
|
||||||
"Withflags",
|
"Withflags",
|
||||||
|
"withs",
|
||||||
"Wolof",
|
"Wolof",
|
||||||
"WONTFIX",
|
"WONTFIX",
|
||||||
|
"wordcount",
|
||||||
|
"wraping",
|
||||||
"wrongclienttype",
|
"wrongclienttype",
|
||||||
"wrongpassword",
|
"wrongpassword",
|
||||||
"wrongtype",
|
"wrongtype",
|
||||||
@ -863,6 +1052,7 @@
|
|||||||
"xcrun",
|
"xcrun",
|
||||||
"xgettext",
|
"xgettext",
|
||||||
"xlink",
|
"xlink",
|
||||||
|
"Xmark",
|
||||||
"xzvf",
|
"xzvf",
|
||||||
"yarg",
|
"yarg",
|
||||||
"yosay",
|
"yosay",
|
||||||
@ -949,6 +1139,8 @@
|
|||||||
"ประเทศไทย",
|
"ประเทศไทย",
|
||||||
"ປະຊາຊົນລາວ",
|
"ປະຊາຊົນລາວ",
|
||||||
"မြန်မာ",
|
"မြန်မာ",
|
||||||
"កម្ពុជា"
|
"កម្ពុជា",
|
||||||
]
|
"clike"
|
||||||
|
],
|
||||||
|
"enabled": true
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ module.exports = {
|
|||||||
// '**/*.ts?(x)': () => 'npm run tsc',
|
// '**/*.ts?(x)': () => 'npm run tsc',
|
||||||
'*.{js,jsx,ts,tsx}': [
|
'*.{js,jsx,ts,tsx}': [
|
||||||
'yarn checkIgnoredFiles',
|
'yarn checkIgnoredFiles',
|
||||||
// 'yarn checkLibPaths',
|
'yarn spellcheck',
|
||||||
'yarn packageJsonLint',
|
'yarn packageJsonLint',
|
||||||
'yarn linter-precommit',
|
'yarn linter-precommit',
|
||||||
],
|
],
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
"crowdin": "crowdin",
|
"crowdin": "crowdin",
|
||||||
"crowdinDownload": "crowdin download",
|
"crowdinDownload": "crowdin download",
|
||||||
"crowdinUpload": "crowdin upload",
|
"crowdinUpload": "crowdin upload",
|
||||||
"cspell": "cspell",
|
|
||||||
"dependencyTree": "madge",
|
"dependencyTree": "madge",
|
||||||
"generateTypes": "node packages/tools/generate-database-types",
|
"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",
|
"linkChecker": "linkchecker https://joplinapp.org/ && linkchecker --check-extern https://joplinapp.org/api/references/plugin_api/classes/joplin.html",
|
||||||
@ -52,6 +51,7 @@
|
|||||||
"releaseServer": "node packages/tools/release-server.js",
|
"releaseServer": "node packages/tools/release-server.js",
|
||||||
"setupNewRelease": "node ./packages/tools/setupNewRelease",
|
"setupNewRelease": "node ./packages/tools/setupNewRelease",
|
||||||
"spellcheck": "node packages/tools/spellcheck.js",
|
"spellcheck": "node packages/tools/spellcheck.js",
|
||||||
|
"spellcheck-base": "cspell --no-progress --no-summary --config cspell.json",
|
||||||
"tagServerLatest": "node packages/tools/tagServerLatest.js",
|
"tagServerLatest": "node packages/tools/tagServerLatest.js",
|
||||||
"test-ci": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 2 run test-ci",
|
"test-ci": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 2 run test-ci",
|
||||||
"test": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 2 run test",
|
"test": "yarn workspaces foreach --parallel --verbose --interlaced --jobs 2 run test",
|
||||||
|
@ -82,7 +82,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
lines.push('## Authorisation');
|
lines.push('## Authorisation');
|
||||||
lines.push('');
|
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('');
|
||||||
lines.push('This would be an example of valid cURL call using a token:');
|
lines.push('This would be an example of valid cURL call using a token:');
|
||||||
lines.push('');
|
lines.push('');
|
||||||
@ -149,7 +149,7 @@ class Command extends BaseCommand {
|
|||||||
lines.push('');
|
lines.push('');
|
||||||
lines.push('```shell\ncurl http://localhost:41184/notes?order_by=updated_time&order_dir=ASC&limit=10&page=2\n```');
|
lines.push('```shell\ncurl http://localhost:41184/notes?order_by=updated_time&order_dir=ASC&limit=10&page=2\n```');
|
||||||
lines.push('');
|
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('');
|
||||||
lines.push('As an example the pseudo-code below could be used to fetch all the notes:');
|
lines.push('As an example the pseudo-code below could be used to fetch all the notes:');
|
||||||
lines.push('');
|
lines.push('');
|
||||||
@ -199,7 +199,7 @@ async function fetchAllNotes() {
|
|||||||
|
|
||||||
lines.push('## Item type IDs');
|
lines.push('## Item type IDs');
|
||||||
lines.push('');
|
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('');
|
||||||
lines.push('Name | Value');
|
lines.push('Name | Value');
|
||||||
lines.push('---- | -----');
|
lines.push('---- | -----');
|
||||||
|
@ -86,7 +86,7 @@ class Command extends BaseCommand {
|
|||||||
return true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ describeIfCompatible('services_KeychainService', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should delete db settings if they have been saved in keychain', (async () => {
|
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;
|
KeychainService.instance().enabled = false;
|
||||||
|
|
||||||
Setting.setValue('sync.5.password', 'password');
|
Setting.setValue('sync.5.password', 'password');
|
||||||
|
@ -26,7 +26,7 @@ async function browserCaptureVisibleTabs(windowId) {
|
|||||||
|
|
||||||
// This is supposed to be the default quality, but in fact Firefox 82+
|
// 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
|
// 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://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/extensionTypes/ImageDetails
|
||||||
// https://discourse.joplinapp.org/t/clip-screenshot-image-quality/12302/4
|
// https://discourse.joplinapp.org/t/clip-screenshot-image-quality/12302/4
|
||||||
quality: 92,
|
quality: 92,
|
||||||
|
@ -78,7 +78,7 @@ export const KeymapConfigScreen = ({ themeId }: KeymapConfigScreenProps) => {
|
|||||||
// KeymapService is already synchronized with the in-state keymap
|
// KeymapService is already synchronized with the in-state keymap
|
||||||
await keymapService.saveCustomKeymap(filePath);
|
await keymapService.saveCustomKeymap(filePath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
bridge().showerrororMessageBox(error.message);
|
bridge().showErrorMessageBox(error.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -237,7 +237,7 @@ class MainScreenComponent extends React.Component<Props, State> {
|
|||||||
try {
|
try {
|
||||||
output = loadLayout(Object.keys(userLayout).length ? userLayout : null, defaultLayout, rootLayoutSize);
|
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
|
// 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
|
// here. It could be due to the deprecated plugin API, which allowed
|
||||||
// creating panel without a key, although in this case it should
|
// creating panel without a key, although in this case it should
|
||||||
@ -264,7 +264,7 @@ class MainScreenComponent extends React.Component<Props, State> {
|
|||||||
public setupAppCloseHandling() {
|
public setupAppCloseHandling() {
|
||||||
this.waitForNotesSavedIID_ = null;
|
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"
|
// to close. The renderer process must respond with the "appCloseReply"
|
||||||
// and tell the main process whether the app can really be closed or not.
|
// 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.
|
// For example, it cannot be closed right away if a note is being saved.
|
||||||
|
@ -19,7 +19,7 @@ export const runtime = (comp: any): CommandRuntime => {
|
|||||||
return { value: a.id, label: a.title };
|
return { value: a.id, label: a.title };
|
||||||
})
|
})
|
||||||
.sort((a: any, b: any) => {
|
.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
|
// but treats caps as equal
|
||||||
return a.label.localeCompare(b.label, undefined, { sensitivity: 'accent' });
|
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 };
|
return { value: a.id, label: a.title };
|
||||||
})
|
})
|
||||||
.sort((a: any, b: any) => {
|
.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
|
// but treats caps as equal
|
||||||
return a.label.localeCompare(b.label, undefined, { sensitivity: 'accent' });
|
return a.label.localeCompare(b.label, undefined, { sensitivity: 'accent' });
|
||||||
});
|
});
|
||||||
|
@ -563,7 +563,7 @@ function useMenu(props: Props) {
|
|||||||
|
|
||||||
const rootMenuFile = {
|
const rootMenuFile = {
|
||||||
// Using a dummy entry for macOS here, because first menu
|
// 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'),
|
label: shim.isMac() ? '&JoplinMainMenu' : _('&File'),
|
||||||
// `&` before one of the char in the label name mean, that
|
// `&` before one of the char in the label name mean, that
|
||||||
// <Alt + F> will open this menu. It's needed because electron
|
// <Alt + F> will open this menu. It's needed because electron
|
||||||
|
@ -117,7 +117,7 @@ const useContextMenu = (props: ContextMenuProps) => {
|
|||||||
|
|
||||||
// CodeMirror 5 only:
|
// CodeMirror 5 only:
|
||||||
// Typically CodeMirror handles all interactions itself (highlighting etc.)
|
// 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
|
// The result is that CodeMirror doesn't know what's been selected and doesn't
|
||||||
// move the cursor into the correct location.
|
// move the cursor into the correct location.
|
||||||
// and when the user selects a new spelling it will be inserted in the wrong location
|
// and when the user selects a new spelling it will be inserted in the wrong location
|
||||||
|
@ -62,7 +62,7 @@ export default function useEditorSearch(CodeMirror: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Highlights the currently active found work
|
// 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
|
// 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) {
|
function highlightSearch(cm: any, searchTerm: RegExp, index: number, scrollTo: boolean, withSelection: boolean) {
|
||||||
const cursor = cm.getSearchCursor(searchTerm);
|
const cursor = cm.getSearchCursor(searchTerm);
|
||||||
@ -135,7 +135,7 @@ export default function useEditorSearch(CodeMirror: any) {
|
|||||||
if (error.name !== 'SyntaxError') {
|
if (error.name !== 'SyntaxError') {
|
||||||
throw error;
|
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
|
// when the input is really big, this catch is here to avoid the application crashing
|
||||||
// https://github.com/laurent22/joplin/issues/7634
|
// https://github.com/laurent22/joplin/issues/7634
|
||||||
console.error('Error while trying to highlight words from search: ', error);
|
console.error('Error while trying to highlight words from search: ', error);
|
||||||
|
@ -115,7 +115,7 @@ export default function useScrollHandler(editorRef: any, webviewRef: any, onScro
|
|||||||
if (!isNaN(editorPercent)) {
|
if (!isNaN(editorPercent)) {
|
||||||
// when switching to another note, the percent can sometimes be NaN
|
// when switching to another note, the percent can sometimes be NaN
|
||||||
// this is coming from `gui/NoteEditor/NoteBody/CodeMirror/utils/useScrollUtils.ts`
|
// 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
|
// https://github.com/laurent22/joplin/issues/4797
|
||||||
if (!ignored) {
|
if (!ignored) {
|
||||||
// calculates GUI-independent line-based percent
|
// calculates GUI-independent line-based percent
|
||||||
|
@ -507,7 +507,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditor
|
|||||||
color: ${theme.codeColor};
|
color: ${theme.codeColor};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Negative margins are needed to componsate for the border */
|
/* Negative margins are needed to compensate for the border */
|
||||||
div.CodeMirror span.cm-comment.cm-jn-inline-code:not(.cm-search-marker):not(.cm-fat-cursor-mark):not(.cm-search-marker-selected):not(.CodeMirror-selectedtext) {
|
div.CodeMirror span.cm-comment.cm-jn-inline-code:not(.cm-search-marker):not(.cm-fat-cursor-mark):not(.cm-search-marker-selected):not(.CodeMirror-selectedtext) {
|
||||||
border: 1px solid ${theme.codeBorderColor};
|
border: 1px solid ${theme.codeBorderColor};
|
||||||
background-color: ${codeBackgroundColor};
|
background-color: ${codeBackgroundColor};
|
||||||
|
@ -258,7 +258,7 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
|
|||||||
if (joplinCommandToTinyMceCommands[cmd.name] === true) {
|
if (joplinCommandToTinyMceCommands[cmd.name] === true) {
|
||||||
// Already handled in useWindowCommandHandlers.ts
|
// Already handled in useWindowCommandHandlers.ts
|
||||||
} else if (joplinCommandToTinyMceCommands[cmd.name] === false) {
|
} else if (joplinCommandToTinyMceCommands[cmd.name] === false) {
|
||||||
// Explicitely not supported
|
// explicitly not supported
|
||||||
} else {
|
} else {
|
||||||
const tinyMceCmd: TinyMceCommand = { ...(joplinCommandToTinyMceCommands[cmd.name] as TinyMceCommand) };
|
const tinyMceCmd: TinyMceCommand = { ...(joplinCommandToTinyMceCommands[cmd.name] as TinyMceCommand) };
|
||||||
if (!('ui' in tinyMceCmd)) tinyMceCmd.ui = false;
|
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
|
// when pasting text with Ctrl+Shift+V, the format should be
|
||||||
// ignored. In this case,
|
// 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
|
// string, but the clipboard.readHTML() still returns the
|
||||||
// formatted text.
|
// formatted text.
|
||||||
const pastedHtml = event.clipboardData.getData('text/html') ? clipboard.readHTML() : '';
|
const pastedHtml = event.clipboardData.getData('text/html') ? clipboard.readHTML() : '';
|
||||||
|
@ -468,7 +468,7 @@ function NoteEditor(props: NoteEditorProps) {
|
|||||||
isSafeMode: props.isSafeMode,
|
isSafeMode: props.isSafeMode,
|
||||||
useCustomPdfViewer: props.useCustomPdfViewer,
|
useCustomPdfViewer: props.useCustomPdfViewer,
|
||||||
// We need it to identify the context for which media is rendered.
|
// 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,
|
noteId: props.noteId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ describe('clipboardUtils', () => {
|
|||||||
expect(copyableContent.html).toEqual(`<div><img src="${localImage}"></div>`);
|
expect(copyableContent.html).toEqual(`<div><img src="${localImage}"></div>`);
|
||||||
});
|
});
|
||||||
|
|
||||||
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 localImage1 = 'file:///home/some/path/test1.jpg';
|
||||||
const localImage2 = 'file:///home/some/path/test2.jpg';
|
const localImage2 = 'file:///home/some/path/test2.jpg';
|
||||||
const localImage3 = 'file:///home/some/path/test3.jpg';
|
const localImage3 = 'file:///home/some/path/test3.jpg';
|
||||||
|
@ -18,7 +18,7 @@ function htmlToMd(): HtmlToMd {
|
|||||||
|
|
||||||
function removeImageUrlAttributes(htmlContent: string): string {
|
function removeImageUrlAttributes(htmlContent: string): string {
|
||||||
// We need to remove extra url params from the image URLs while copying
|
// 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.
|
// an extra parameter in it's path.
|
||||||
// Related to - https://github.com/laurent22/joplin/issues/4602
|
// Related to - https://github.com/laurent22/joplin/issues/4602
|
||||||
const removeParametersFromUrl = (url: string) => {
|
const removeParametersFromUrl = (url: string) => {
|
||||||
|
@ -75,7 +75,7 @@ export default function useFormNote(dependencies: HookDependencies) {
|
|||||||
|
|
||||||
// Increasing the value of this counter cancels any ongoing note refreshes and starts
|
// Increasing the value of this counter cancels any ongoing note refreshes and starts
|
||||||
// a new refresh.
|
// a new refresh.
|
||||||
const [formNoteRefeshScheduled, setFormNoteRefreshScheduled] = useState<number>(0);
|
const [formNoteRefreshScheduled, setFormNoteRefreshScheduled] = useState<number>(0);
|
||||||
|
|
||||||
async function initNoteState(n: any) {
|
async function initNoteState(n: any) {
|
||||||
let originalCss = '';
|
let originalCss = '';
|
||||||
@ -114,7 +114,7 @@ export default function useFormNote(dependencies: HookDependencies) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (formNoteRefeshScheduled <= 0) return () => {};
|
if (formNoteRefreshScheduled <= 0) return () => {};
|
||||||
|
|
||||||
reg.logger().info('Sync has finished and note has never been changed - reloading it');
|
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 () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
};
|
};
|
||||||
}, [formNoteRefeshScheduled, noteId]);
|
}, [formNoteRefreshScheduled, noteId]);
|
||||||
|
|
||||||
const refreshFormNote = useCallback(() => {
|
const refreshFormNote = useCallback(() => {
|
||||||
// Increase the counter to cancel any ongoing refresh attempts
|
// Increase the counter to cancel any ongoing refresh attempts
|
||||||
// and start a new one.
|
// and start a new one.
|
||||||
setFormNoteRefreshScheduled(formNoteRefeshScheduled + 1);
|
setFormNoteRefreshScheduled(formNoteRefreshScheduled + 1);
|
||||||
}, [formNoteRefeshScheduled]);
|
}, [formNoteRefreshScheduled]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Check that synchronisation has just finished - and
|
// Check that synchronisation has just finished - and
|
||||||
|
@ -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
|
// 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.
|
// 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.
|
// although I couldn't find an upstream issue.
|
||||||
//
|
//
|
||||||
// Setting the value only once after a short time, for example 10ms, helps
|
// Setting the value only once after a short time, for example 10ms, helps
|
||||||
|
@ -138,7 +138,7 @@ function NoteListItem(props: NoteListItemProps, ref: any) {
|
|||||||
if (error.name !== 'SyntaxError') {
|
if (error.name !== 'SyntaxError') {
|
||||||
throw error;
|
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
|
// when the input is really big, this catch is here to avoid the application crashing
|
||||||
// https://github.com/laurent22/joplin/issues/7634
|
// https://github.com/laurent22/joplin/issues/7634
|
||||||
console.error('Error while trying to highlight words from search: ', error);
|
console.error('Error while trying to highlight words from search: ', error);
|
||||||
|
@ -25,7 +25,7 @@ const getNoteTitleHtml = (highlightedWords: string[], displayTitle: string) => {
|
|||||||
if (error.name !== 'SyntaxError') {
|
if (error.name !== 'SyntaxError') {
|
||||||
throw error;
|
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
|
// when the input is really big, this catch is here to avoid the application crashing
|
||||||
// https://github.com/laurent22/joplin/issues/7634
|
// https://github.com/laurent22/joplin/issues/7634
|
||||||
// console.error('Error while trying to highlight words from search: ', error);
|
// console.error('Error while trying to highlight words from search: ', error);
|
||||||
|
@ -155,7 +155,7 @@ class NoteRevisionViewerComponent extends React.PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async webview_ipcMessage(event: any) {
|
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.
|
// 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.
|
// We try to get most links work though, except for internal (joplin://) links.
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ export default class PromptDialog extends React.Component<Props, any> {
|
|||||||
const onKeyDown = (event: any) => {
|
const onKeyDown = (event: any) => {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter') {
|
||||||
// If the dropdown is open, we don't close the dialog - instead
|
// 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.
|
// we confirm the dialog.
|
||||||
if ((this.props.inputType === 'tags' || this.props.inputType === 'dropdown') && this.menuIsOpened_) {
|
if ((this.props.inputType === 'tags' || this.props.inputType === 'dropdown') && this.menuIsOpened_) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
@ -11,7 +11,7 @@ export interface LayoutItemSizes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Container always take the full space while the items within it need to
|
// 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 {
|
export function itemSize(item: LayoutItem, parent: LayoutItem | null, sizes: LayoutItemSizes, isContainer: boolean): Size {
|
||||||
const parentResizableRight = !!parent && parent.resizableRight;
|
const parentResizableRight = !!parent && parent.resizableRight;
|
||||||
const parentResizableBottom = !!parent && parent.resizableBottom;
|
const parentResizableBottom = !!parent && parent.resizableBottom;
|
||||||
|
@ -89,7 +89,7 @@ function itemShouldBeVisible(item: LayoutItem): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If all children of a container are hidden, the container should be
|
// 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) {
|
function updateContainerVisibility(_itemIndex: number, itemDraft: LayoutItem, _parent: LayoutItem) {
|
||||||
if (itemDraft.children) {
|
if (itemDraft.children) {
|
||||||
itemDraft.visible = itemShouldBeVisible(itemDraft);
|
itemDraft.visible = itemShouldBeVisible(itemDraft);
|
||||||
|
@ -41,14 +41,14 @@ async function exportDebugReportClick() {
|
|||||||
function StatusScreen(props: Props) {
|
function StatusScreen(props: Props) {
|
||||||
const [report, setReport] = useState<ReportSection[]>([]);
|
const [report, setReport] = useState<ReportSection[]>([]);
|
||||||
|
|
||||||
async function resfreshScreen() {
|
async function refreshScreen() {
|
||||||
const service = new ReportService();
|
const service = new ReportService();
|
||||||
const r = await service.status(Setting.value('sync.target'));
|
const r = await service.status(Setting.value('sync.target'));
|
||||||
setReport(r);
|
setReport(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void resfreshScreen();
|
void refreshScreen();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const theme = themeStyle(props.themeId);
|
const theme = themeStyle(props.themeId);
|
||||||
@ -86,7 +86,7 @@ function StatusScreen(props: Props) {
|
|||||||
if (section.canRetryAll) {
|
if (section.canRetryAll) {
|
||||||
items.push(renderSectionRetryAll(`${key}_${section.title}`, async () => {
|
items.push(renderSectionRetryAll(`${key}_${section.title}`, async () => {
|
||||||
await section.retryAllHandler();
|
await section.retryAllHandler();
|
||||||
void resfreshScreen();
|
void refreshScreen();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
return items;
|
return items;
|
||||||
@ -112,7 +112,7 @@ function StatusScreen(props: Props) {
|
|||||||
if (item.canRetry) {
|
if (item.canRetry) {
|
||||||
const onClick = async () => {
|
const onClick = async () => {
|
||||||
await item.retryHandler();
|
await item.retryHandler();
|
||||||
void resfreshScreen();
|
void refreshScreen();
|
||||||
};
|
};
|
||||||
|
|
||||||
retryLink = (
|
retryLink = (
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
// same effect.
|
// same effect.
|
||||||
//
|
//
|
||||||
// It's still reliable because the lifecyle of adding the CSS and removing on
|
// 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.
|
// page.
|
||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
@ -109,7 +109,7 @@
|
|||||||
let ignoreNextScrollEventCount_ = 0;
|
let ignoreNextScrollEventCount_ = 0;
|
||||||
|
|
||||||
// ignoreNextScrollEvent() provides a way to skip scroll events for a certain duration.
|
// 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
|
// so as to differentiate scroll events generated by the user (when scrolling the view) and those
|
||||||
// generated by the application.
|
// generated by the application.
|
||||||
function ignoreNextScrollEvent() {
|
function ignoreNextScrollEvent() {
|
||||||
|
@ -15,7 +15,7 @@ describe('notesSortOrderUtils', () => {
|
|||||||
expect(notesSortOrderFieldArray()).toStrictEqual(expected);
|
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('user_updated_time')).toBe('user_created_time');
|
||||||
expect(notesSortOrderNextField('order')).toBe('user_updated_time');
|
expect(notesSortOrderNextField('order')).toBe('user_updated_time');
|
||||||
});
|
});
|
||||||
|
@ -22,7 +22,7 @@ export const notesSortOrderNextField = (currentField: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const setNotesSortOrder = (field?: string, reverse?: boolean) => {
|
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.
|
// reverse: whether the sort order is reversed or not. undefined means toggling.
|
||||||
let nextField = field;
|
let nextField = field;
|
||||||
let nextReverse = reverse;
|
let nextReverse = reverse;
|
||||||
|
@ -3,7 +3,7 @@ import { copy } from 'fs-extra';
|
|||||||
import { dirname, join } from 'path';
|
import { dirname, join } from 'path';
|
||||||
|
|
||||||
const copy7Zip = async () => {
|
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.
|
// the npm_config_target_arch and npm_config_target_platform environment variables.
|
||||||
//
|
//
|
||||||
// These are the same environment variables used by yarn when downloading dependencies.
|
// These are the same environment variables used by yarn when downloading dependencies.
|
||||||
|
@ -15,7 +15,7 @@ jest.doMock('../bridge', () => ({
|
|||||||
'--profile', currentProfileDirectory,
|
'--profile', currentProfileDirectory,
|
||||||
],
|
],
|
||||||
env: () => 'dev',
|
env: () => 'dev',
|
||||||
appName: () => 'joplin-destkop',
|
appName: () => 'joplin-desktop',
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ export default function useOnMessage(
|
|||||||
noteBody: string,
|
noteBody: string,
|
||||||
callbacks: MessageCallbacks,
|
callbacks: MessageCallbacks,
|
||||||
) {
|
) {
|
||||||
// Dectructure callbacks. Because we have that ({ a: 1 }) !== ({ a: 1 }),
|
// Destructure callbacks. Because we have that ({ a: 1 }) !== ({ a: 1 }),
|
||||||
// we can expect the `callbacks` variable from the last time useOnMessage was called to
|
// we can expect the `callbacks` variable from the last time useOnMessage was called to
|
||||||
// not equal the current` callbacks` variable, even if the callbacks themselves are the
|
// not equal the current` callbacks` variable, even if the callbacks themselves are the
|
||||||
// same.
|
// same.
|
||||||
|
@ -75,7 +75,7 @@ export default function useSource(
|
|||||||
// If a checkbox in a note is ticked, the body changes, which normally would
|
// If a checkbox in a note is ticked, the body changes, which normally would
|
||||||
// trigger a re-render of this component, which has the unfortunate side
|
// trigger a re-render of this component, which has the unfortunate side
|
||||||
// effect of making the view scroll back to the top. This re-rendering
|
// effect of making the view scroll back to the top. This re-rendering
|
||||||
// however is uncessary since the component is already visually updated via
|
// however is unnecessary since the component is already visually updated via
|
||||||
// JS. So here, if the note has not changed, we prevent the component from
|
// JS. So here, if the note has not changed, we prevent the component from
|
||||||
// updating. This fixes the above issue. A drawback of this is if the note
|
// updating. This fixes the above issue. A drawback of this is if the note
|
||||||
// is updated via sync, this change will not be displayed immediately.
|
// is updated via sync, this change will not be displayed immediately.
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
// NoteEditor.tsx into the webview.
|
// NoteEditor.tsx into the webview.
|
||||||
//
|
//
|
||||||
// In general, since this file is harder to debug due to the intermediate built
|
// In general, since this file is harder to debug due to the intermediate built
|
||||||
// step, it's better to keep it as light as possible - it shoud just be a light
|
// step, it's better to keep it as light as possible - it should just be a light
|
||||||
// wrapper to access CodeMirror functionalities. Anything else should be done
|
// wrapper to access CodeMirror functionalities. Anything else should be done
|
||||||
// from NoteEditor.tsx.
|
// from NoteEditor.tsx.
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ const useCss = (editorTheme: Theme) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Hide the save/close icons on small screens. This isn't done in the upstream
|
/* 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
|
(icons can be used to suggest the meaning of a button when a translation is
|
||||||
unavailable). */
|
unavailable). */
|
||||||
.toolbar-edge-toolbar:not(.one-row) .toolwidget-tag--save .toolbar-icon,
|
.toolbar-edge-toolbar:not(.one-row) .toolwidget-tag--save .toolbar-icon,
|
||||||
|
@ -102,7 +102,7 @@ export const createJsDrawEditor = (
|
|||||||
|
|
||||||
saveButton = toolbar.addSaveButton(saveNow);
|
saveButton = toolbar.addSaveButton(saveNow);
|
||||||
|
|
||||||
// Load and save toolbar-realated state (e.g. pen sizes/colors).
|
// Load and save toolbar-related state (e.g. pen sizes/colors).
|
||||||
restoreToolbarState(toolbar, initialToolbarState);
|
restoreToolbarState(toolbar, initialToolbarState);
|
||||||
listenToolbarState(editor, toolbar);
|
listenToolbarState(editor, toolbar);
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ const watchEditorForTemplateChanges = (
|
|||||||
if (!editor.image.getAutoresizeEnabled()) {
|
if (!editor.image.getAutoresizeEnabled()) {
|
||||||
backgroundSize = editor.getImportExportRect().size;
|
backgroundSize = editor.getImportExportRect().size;
|
||||||
|
|
||||||
// Constrain the size: Don't allow an extremely small or extremely large tempalte.
|
// Constrain the size: Don't allow an extremely small or extremely large template.
|
||||||
// Map components to constrained components.
|
// Map components to constrained components.
|
||||||
backgroundSize = backgroundSize.map(component => {
|
backgroundSize = backgroundSize.map(component => {
|
||||||
const minDimen = 45;
|
const minDimen = 45;
|
||||||
|
@ -92,7 +92,7 @@ function useHtml(css: string): string {
|
|||||||
.cm-scroller {
|
.cm-scroller {
|
||||||
overflow: none;
|
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. */
|
Don't use 100vh to prevent a scrollbar being present for empty notes. */
|
||||||
min-height: 80vh;
|
min-height: 80vh;
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ export const SearchPanel = (props: SearchPanelProps) => {
|
|||||||
control.setSearchState(newState);
|
control.setSearchState(newState);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Creates a TextInut with the given parameters
|
// Creates a TextInput with the given parameters
|
||||||
const createInput = (
|
const createInput = (
|
||||||
placeholder: string, value: string, onChange: OnChangeCallback, autoFocus: boolean,
|
placeholder: string, value: string, onChange: OnChangeCallback, autoFocus: boolean,
|
||||||
) => {
|
) => {
|
||||||
|
@ -64,7 +64,7 @@ class AppNavComponent extends Component<Props, State> {
|
|||||||
private keyboardWillChangeFrame = (evt: KeyboardEvent) => {
|
private keyboardWillChangeFrame = (evt: KeyboardEvent) => {
|
||||||
const windowWidth = Dimensions.get('window').width;
|
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
|
// See https://github.com/facebook/react-native/issues/29473#issuecomment-696658937
|
||||||
this.setState({
|
this.setState({
|
||||||
floatingKeyboardEnabled: evt.endCoordinates.width < windowWidth,
|
floatingKeyboardEnabled: evt.endCoordinates.width < windowWidth,
|
||||||
@ -101,7 +101,7 @@ class AppNavComponent extends Component<Props, State> {
|
|||||||
|
|
||||||
const style = { flex: 1, backgroundColor: theme.backgroundColor };
|
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.
|
// height. Don't use the KeyboardAvoidingView when the floating keyboard is enabled.
|
||||||
// See https://github.com/facebook/react-native/issues/29473
|
// See https://github.com/facebook/react-native/issues/29473
|
||||||
const keyboardAvoidingViewEnabled = !this.state.floatingKeyboardEnabled;
|
const keyboardAvoidingViewEnabled = !this.state.floatingKeyboardEnabled;
|
||||||
|
@ -80,7 +80,7 @@ class ConfigScreenComponent extends BaseScreenComponent<ConfigScreenProps, Confi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private checkSyncConfig_ = async () => {
|
private checkSyncConfig_ = async () => {
|
||||||
// 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
|
// 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 prevIgnoreTlsErrors = await setIgnoreTlsErrors(this.state.settings['net.ignoreTlsErrors']);
|
||||||
const result = await shared.checkSyncConfig(this, this.state.settings);
|
const result = await shared.checkSyncConfig(this, this.state.settings);
|
||||||
@ -257,7 +257,7 @@ class ConfigScreenComponent extends BaseScreenComponent<ConfigScreenProps, Confi
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleNavigateToNewScren = async (): Promise<boolean> => {
|
private handleNavigateToNewScreen = async (): Promise<boolean> => {
|
||||||
await this.promptSaveChanges();
|
await this.promptSaveChanges();
|
||||||
|
|
||||||
// Continue navigation
|
// Continue navigation
|
||||||
@ -306,14 +306,14 @@ class ConfigScreenComponent extends BaseScreenComponent<ConfigScreenProps, Confi
|
|||||||
}
|
}
|
||||||
|
|
||||||
BackButtonService.addHandler(this.handleBackButtonPress);
|
BackButtonService.addHandler(this.handleBackButtonPress);
|
||||||
NavService.addHandler(this.handleNavigateToNewScren);
|
NavService.addHandler(this.handleNavigateToNewScreen);
|
||||||
Dimensions.addEventListener('change', this.updateSidebarWidth);
|
Dimensions.addEventListener('change', this.updateSidebarWidth);
|
||||||
this.updateSidebarWidth();
|
this.updateSidebarWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
BackButtonService.removeHandler(this.handleBackButtonPress);
|
BackButtonService.removeHandler(this.handleBackButtonPress);
|
||||||
NavService.removeHandler(this.handleNavigateToNewScren);
|
NavService.removeHandler(this.handleNavigateToNewScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderButton(key: string, title: string, clickHandler: ()=> void, options: any = null) {
|
private renderButton(key: string, title: string, clickHandler: ()=> void, options: any = null) {
|
||||||
|
@ -67,13 +67,13 @@ class LogScreenComponent extends BaseScreenComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.refreshLogTimeout = null;
|
this.refreshLogTimeout = null;
|
||||||
void this.resfreshLogEntries();
|
void this.refreshLogEntries();
|
||||||
}, 600);
|
}, 600);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount() {
|
public override componentDidMount() {
|
||||||
void this.resfreshLogEntries();
|
void this.refreshLogEntries();
|
||||||
|
|
||||||
if (this.props.navigation.state.defaultFilter) {
|
if (this.props.navigation.state.defaultFilter) {
|
||||||
this.setState({ filter: this.props.navigation.state.defaultFilter });
|
this.setState({ filter: this.props.navigation.state.defaultFilter });
|
||||||
@ -155,7 +155,7 @@ class LogScreenComponent extends BaseScreenComponent<Props, State> {
|
|||||||
return levels;
|
return levels;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async resfreshLogEntries(showErrorsOnly: boolean = null) {
|
private async refreshLogEntries(showErrorsOnly: boolean = null) {
|
||||||
if (showErrorsOnly === null) showErrorsOnly = this.state.showErrorsOnly;
|
if (showErrorsOnly === null) showErrorsOnly = this.state.showErrorsOnly;
|
||||||
|
|
||||||
const limit = 1000;
|
const limit = 1000;
|
||||||
@ -168,7 +168,7 @@ class LogScreenComponent extends BaseScreenComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private toggleErrorsOnly() {
|
private toggleErrorsOnly() {
|
||||||
void this.resfreshLogEntries(!this.state.showErrorsOnly);
|
void this.refreshLogEntries(!this.state.showErrorsOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
private formatLogEntry(item: any) {
|
private formatLogEntry(item: any) {
|
||||||
@ -224,7 +224,7 @@ class LogScreenComponent extends BaseScreenComponent<Props, State> {
|
|||||||
<Button
|
<Button
|
||||||
title={_('Refresh')}
|
title={_('Refresh')}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
void this.resfreshLogEntries();
|
void this.refreshLogEntries();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
@ -638,7 +638,7 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B
|
|||||||
this.scheduleSave();
|
this.scheduleSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
private onPlainEdtiorSelectionChange = (event: NativeSyntheticEvent<any>) => {
|
private onPlainEditorSelectionChange = (event: NativeSyntheticEvent<any>) => {
|
||||||
this.selection = event.nativeEvent.selection;
|
this.selection = event.nativeEvent.selection;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -883,7 +883,7 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async attachPhoto_onPress() {
|
private async attachPhoto_onPress() {
|
||||||
// the selection Limit should be specfied. I think 200 is enough?
|
// the selection Limit should be specified. I think 200 is enough?
|
||||||
const response: ImagePickerResponse = await launchImageLibrary({ mediaType: 'photo', includeBase64: false, selectionLimit: 200 });
|
const response: ImagePickerResponse = await launchImageLibrary({ mediaType: 'photo', includeBase64: false, selectionLimit: 200 });
|
||||||
|
|
||||||
if (response.errorCode) {
|
if (response.errorCode) {
|
||||||
@ -938,7 +938,7 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B
|
|||||||
if (!resource) {
|
if (!resource) {
|
||||||
resource = await this.attachNewDrawing(svgData);
|
resource = await this.attachNewDrawing(svgData);
|
||||||
|
|
||||||
// Set resouce and file path to allow
|
// Set resource and file path to allow
|
||||||
// 1. subsequent saves to update the resource
|
// 1. subsequent saves to update the resource
|
||||||
// 2. the editor to load from the resource's filepath (can happen
|
// 2. the editor to load from the resource's filepath (can happen
|
||||||
// if the webview is reloaded).
|
// if the webview is reloaded).
|
||||||
@ -974,7 +974,7 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B
|
|||||||
if (this.state.mode === 'edit') {
|
if (this.state.mode === 'edit') {
|
||||||
// Create a new empty drawing and attach it now, before the image editor is opened.
|
// Create a new empty drawing and attach it now, before the image editor is opened.
|
||||||
// With the present structure of Note.tsx, the we can't use this.editorRef while
|
// With the present structure of Note.tsx, the we can't use this.editorRef while
|
||||||
// the image editor is open, and thus can't attach drawings at the cursor locaiton.
|
// the image editor is open, and thus can't attach drawings at the cursor location.
|
||||||
const resource = await this.attachNewDrawing('');
|
const resource = await this.attachNewDrawing('');
|
||||||
await this.editDrawing(resource);
|
await this.editDrawing(resource);
|
||||||
} else {
|
} else {
|
||||||
@ -1137,7 +1137,7 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B
|
|||||||
// On iOS, it will show "local files", which means certain files saved from the browser
|
// On iOS, it will show "local files", which means certain files saved from the browser
|
||||||
// and the iCloud files, but it doesn't include photos and images from the CameraRoll
|
// and the iCloud files, but it doesn't include photos and images from the CameraRoll
|
||||||
//
|
//
|
||||||
// On Android, it will depend on the phone, but usually it will allow browing all files and photos.
|
// On Android, it will depend on the phone, but usually it will allow browsing all files and photos.
|
||||||
buttons.push({ text: _('Attach file'), id: 'attachFile' });
|
buttons.push({ text: _('Attach file'), id: 'attachFile' });
|
||||||
|
|
||||||
// Disabled on Android because it doesn't work due to permission issues, but enabled on iOS
|
// Disabled on Android because it doesn't work due to permission issues, but enabled on iOS
|
||||||
@ -1228,7 +1228,7 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B
|
|||||||
|
|
||||||
const output: MenuOptionType[] = [];
|
const output: MenuOptionType[] = [];
|
||||||
|
|
||||||
// The file attachement modules only work in Android >= 5 (Version 21)
|
// The file attachment modules only work in Android >= 5 (Version 21)
|
||||||
// https://github.com/react-community/react-native-image-picker/issues/606
|
// https://github.com/react-community/react-native-image-picker/issues/606
|
||||||
|
|
||||||
// As of 2020-10-13, support for attaching images from the gallery is removed
|
// As of 2020-10-13, support for attaching images from the gallery is removed
|
||||||
@ -1490,7 +1490,7 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B
|
|||||||
// See https://github.com/laurent22/joplin/issues/3041
|
// See https://github.com/laurent22/joplin/issues/3041
|
||||||
|
|
||||||
// IMPORTANT: The TextInput selection is unreliable and cannot be used in a controlled component
|
// IMPORTANT: The TextInput selection is unreliable and cannot be used in a controlled component
|
||||||
// context. In other words, the selection should be considered read-only. For example, if the seleciton
|
// context. In other words, the selection should be considered read-only. For example, if the selection
|
||||||
// is saved to the state in onSelectionChange and the current text in onChangeText, then set
|
// is saved to the state in onSelectionChange and the current text in onChangeText, then set
|
||||||
// back in `selection` and `value` props, it will mostly work. But when typing fast, sooner or
|
// back in `selection` and `value` props, it will mostly work. But when typing fast, sooner or
|
||||||
// later the real selection will be different from what is stored in the state, thus making
|
// later the real selection will be different from what is stored in the state, thus making
|
||||||
@ -1508,7 +1508,7 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B
|
|||||||
multiline={true}
|
multiline={true}
|
||||||
value={note.body}
|
value={note.body}
|
||||||
onChangeText={(text: string) => this.body_changeText(text)}
|
onChangeText={(text: string) => this.body_changeText(text)}
|
||||||
onSelectionChange={this.onPlainEdtiorSelectionChange}
|
onSelectionChange={this.onPlainEditorSelectionChange}
|
||||||
blurOnSubmit={false}
|
blurOnSubmit={false}
|
||||||
selectionColor={theme.textSelectionColor}
|
selectionColor={theme.textSelectionColor}
|
||||||
keyboardAppearance={theme.keyboardAppearance}
|
keyboardAppearance={theme.keyboardAppearance}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
import createEditor from './createEditor';
|
import createEditor from './createEditor';
|
||||||
import Setting from '@joplin/lib/models/Setting';
|
import Setting from '@joplin/lib/models/Setting';
|
||||||
import { forceParsing } from '@codemirror/language';
|
import { forceParsing } from '@codemirror/language';
|
||||||
import loadLangauges from './testUtil/loadLanguages';
|
import loadLanguages from './testUtil/loadLanguages';
|
||||||
|
|
||||||
import { expect, describe, it } from '@jest/globals';
|
import { expect, describe, it } from '@jest/globals';
|
||||||
import createEditorSettings from './testUtil/createEditorSettings';
|
import createEditorSettings from './testUtil/createEditorSettings';
|
||||||
@ -33,7 +33,7 @@ describe('createEditor', () => {
|
|||||||
const initialText = `${headerLineText}\nThis is a test.`;
|
const initialText = `${headerLineText}\nThis is a test.`;
|
||||||
const editorSettings = createEditorSettings(Setting.THEME_LIGHT);
|
const editorSettings = createEditorSettings(Setting.THEME_LIGHT);
|
||||||
|
|
||||||
await loadLangauges();
|
await loadLanguages();
|
||||||
const editor = createEditor(document.body, {
|
const editor = createEditor(document.body, {
|
||||||
initialText,
|
initialText,
|
||||||
settings: editorSettings,
|
settings: editorSettings,
|
||||||
|
@ -3,7 +3,7 @@ import { LanguageDescription, LanguageSupport, StreamLanguage } from '@codemirro
|
|||||||
// To allow auto-indent to work in an unrecognised language, we define an
|
// To allow auto-indent to work in an unrecognised language, we define an
|
||||||
// empty language. Doing so seems to enable auto-indent in code blocks with
|
// empty language. Doing so seems to enable auto-indent in code blocks with
|
||||||
// that language.
|
// that language.
|
||||||
const defaultLangauge = StreamLanguage.define({
|
const defaultLanguage = StreamLanguage.define({
|
||||||
token: (stream) => {
|
token: (stream) => {
|
||||||
stream.next();
|
stream.next();
|
||||||
return null;
|
return null;
|
||||||
@ -12,7 +12,7 @@ const defaultLangauge = StreamLanguage.define({
|
|||||||
|
|
||||||
const defaultLanguageDescription = LanguageDescription.of({
|
const defaultLanguageDescription = LanguageDescription.of({
|
||||||
name: 'default',
|
name: 'default',
|
||||||
support: new LanguageSupport(defaultLangauge),
|
support: new LanguageSupport(defaultLanguage),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default defaultLanguageDescription;
|
export default defaultLanguageDescription;
|
||||||
|
@ -131,7 +131,7 @@ const computeDecorations = (view: EditorView) => {
|
|||||||
const decorations: DecorationDescription[] = [];
|
const decorations: DecorationDescription[] = [];
|
||||||
|
|
||||||
// Add a decoration to all lines between the document position [from] up to
|
// Add a decoration to all lines between the document position [from] up to
|
||||||
// and includeing the position [to].
|
// and including the position [to].
|
||||||
const addDecorationToLines = (from: number, to: number, decoration: Decoration) => {
|
const addDecorationToLines = (from: number, to: number, decoration: Decoration) => {
|
||||||
let pos = from;
|
let pos = from;
|
||||||
while (pos <= to) {
|
while (pos <= to) {
|
||||||
|
@ -278,10 +278,10 @@ export const toggleList = (listType: ListType): Command => {
|
|||||||
const inBlockQuote = (lineContent !== line.text);
|
const inBlockQuote = (lineContent !== line.text);
|
||||||
const indentation = lineContent.match(startingSpaceRegex)[0];
|
const indentation = lineContent.match(startingSpaceRegex)[0];
|
||||||
|
|
||||||
const wrongIndentaton = !isIndentationEquivalent(state, indentation, firstLineIndentation);
|
const wrongIndentation = !isIndentationEquivalent(state, indentation, firstLineIndentation);
|
||||||
|
|
||||||
// If not the right list level,
|
// If not the right list level,
|
||||||
if (inBlockQuote !== firstLineInBlockQuote || wrongIndentaton) {
|
if (inBlockQuote !== firstLineInBlockQuote || wrongIndentation) {
|
||||||
// We'll be starting a new list
|
// We'll be starting a new list
|
||||||
listItemCounter = 1;
|
listItemCounter = 1;
|
||||||
continue;
|
continue;
|
||||||
|
@ -454,7 +454,7 @@ export const toggleRegionFormatGlobally = (
|
|||||||
const startMatch = blockSpec.matcher.start.exec(fromLineText);
|
const startMatch = blockSpec.matcher.start.exec(fromLineText);
|
||||||
const stopMatch = blockSpec.matcher.end.exec(toLineText);
|
const stopMatch = blockSpec.matcher.end.exec(toLineText);
|
||||||
if (startMatch && stopMatch) {
|
if (startMatch && stopMatch) {
|
||||||
// Get start and stop indicies for the starting and ending matches
|
// Get start and stop indices for the starting and ending matches
|
||||||
const [fromMatchFrom, fromMatchTo] = getMatchEndPoints(startMatch, fromLine, inBlockQuote);
|
const [fromMatchFrom, fromMatchTo] = getMatchEndPoints(startMatch, fromLine, inBlockQuote);
|
||||||
const [toMatchFrom, toMatchTo] = getMatchEndPoints(stopMatch, toLine, inBlockQuote);
|
const [toMatchFrom, toMatchTo] = getMatchEndPoints(stopMatch, toLine, inBlockQuote);
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ describe('customEditorCompletion', () => {
|
|||||||
expect(completionStatus(editor.state)).toBe(null);
|
expect(completionStatus(editor.state)).toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should show langaugeData completions when languageData-based autocomplete is enabled', async () => {
|
test('should show languageData completions when languageData-based autocomplete is enabled', async () => {
|
||||||
const editorControl = createEditorControl('');
|
const editorControl = createEditorControl('');
|
||||||
|
|
||||||
const completion = completeFromList(['function']);
|
const completion = completeFromList(['function']);
|
||||||
|
@ -5,7 +5,7 @@ import { SelectionRange, EditorSelection, EditorState, Extension } from '@codemi
|
|||||||
import { EditorView } from '@codemirror/view';
|
import { EditorView } from '@codemirror/view';
|
||||||
import { MarkdownMathExtension } from '../markdown/markdownMathParser';
|
import { MarkdownMathExtension } from '../markdown/markdownMathParser';
|
||||||
import forceFullParse from './forceFullParse';
|
import forceFullParse from './forceFullParse';
|
||||||
import loadLangauges from './loadLanguages';
|
import loadLanguages from './loadLanguages';
|
||||||
|
|
||||||
// Creates and returns a minimal editor with markdown extensions. Waits to return the editor
|
// Creates and returns a minimal editor with markdown extensions. Waits to return the editor
|
||||||
// until all syntax tree tags in `expectedSyntaxTreeTags` exist.
|
// until all syntax tree tags in `expectedSyntaxTreeTags` exist.
|
||||||
@ -15,7 +15,7 @@ const createTestEditor = async (
|
|||||||
expectedSyntaxTreeTags: string[],
|
expectedSyntaxTreeTags: string[],
|
||||||
extraExtensions: Extension[] = [],
|
extraExtensions: Extension[] = [],
|
||||||
): Promise<EditorView> => {
|
): Promise<EditorView> => {
|
||||||
await loadLangauges();
|
await loadLanguages();
|
||||||
|
|
||||||
const editor = new EditorView({
|
const editor = new EditorView({
|
||||||
doc: initialText,
|
doc: initialText,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import allLanguages from '../markdown/codeBlockLanguages/allLanguages';
|
import allLanguages from '../markdown/codeBlockLanguages/allLanguages';
|
||||||
|
|
||||||
// Ensure languages we use are loaded. Without this, tests may randomly fail (LanguageDescriptions
|
// Ensure languages we use are loaded. Without this, tests may randomly fail (LanguageDescriptions
|
||||||
// are loaded asyncronously, in the background).
|
// are loaded asynchronously, in the background).
|
||||||
const loadLangauges = async () => {
|
const loadLanguages = async () => {
|
||||||
for (const lang of allLanguages) {
|
for (const lang of allLanguages) {
|
||||||
await lang.load();
|
await lang.load();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
export default loadLangauges;
|
export default loadLanguages;
|
||||||
|
@ -40,6 +40,8 @@ export { default as Tokenizer } from "./Tokenizer";
|
|||||||
import * as ElementType from "domelementtype";
|
import * as ElementType from "domelementtype";
|
||||||
export { ElementType };
|
export { ElementType };
|
||||||
|
|
||||||
|
// cSpell:disable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of all events that the parser emits.
|
* List of all events that the parser emits.
|
||||||
*
|
*
|
||||||
@ -60,6 +62,8 @@ export const EVENTS = {
|
|||||||
end: 0
|
end: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// cSpell:enable
|
||||||
|
|
||||||
/*
|
/*
|
||||||
All of the following exports exist for backwards-compatibility.
|
All of the following exports exist for backwards-compatibility.
|
||||||
They should probably be removed eventually.
|
They should probably be removed eventually.
|
||||||
|
@ -181,7 +181,7 @@ export interface ExportContext {
|
|||||||
options: ExportOptions;
|
options: ExportOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You can attach your own custom data using this propery - it will then be passed to each event handler, allowing you to keep state from one event to the next.
|
* You can attach your own custom data using this property - it will then be passed to each event handler, allowing you to keep state from one event to the next.
|
||||||
*/
|
*/
|
||||||
userData?: any;
|
userData?: any;
|
||||||
}
|
}
|
||||||
|
@ -126,12 +126,12 @@ describe('EventDispatcher', () => {
|
|||||||
const dispatcher = new Dispatcher();
|
const dispatcher = new Dispatcher();
|
||||||
|
|
||||||
let pass = false;
|
let pass = false;
|
||||||
dispatcher.on('Evnt', () => {
|
dispatcher.on('Event', () => {
|
||||||
pass = true;
|
pass = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(pass).toBe(false);
|
expect(pass).toBe(false);
|
||||||
dispatcher.dispatch('Evnt');
|
dispatcher.dispatch('Event');
|
||||||
expect(pass).toBe(true);
|
expect(pass).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -25,7 +25,7 @@ export default class EventDispatcher<EventKeyType extends string|symbol|number,
|
|||||||
this.listeners[eventName].push(callback);
|
this.listeners[eventName].push(callback);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// Retuns false if the listener has already been removed, true otherwise.
|
// Returns false if the listener has already been removed, true otherwise.
|
||||||
remove: (): boolean => {
|
remove: (): boolean => {
|
||||||
const originalListeners = this.listeners[eventName];
|
const originalListeners = this.listeners[eventName];
|
||||||
this.off(eventName, callback);
|
this.off(eventName, callback);
|
||||||
|
@ -36,7 +36,7 @@ export default class HtmlToMd {
|
|||||||
disableEscapeContent: 'disableEscapeContent' in options ? options.disableEscapeContent : false,
|
disableEscapeContent: 'disableEscapeContent' in options ? options.disableEscapeContent : false,
|
||||||
};
|
};
|
||||||
if (options.convertEmbeddedPdfsToLinks) {
|
if (options.convertEmbeddedPdfsToLinks) {
|
||||||
// Turndown ignores empty <object> tags, so we need to handle this case seperately
|
// Turndown ignores empty <object> tags, so we need to handle this case separately
|
||||||
// https://github.com/mixmark-io/turndown/issues/293#issuecomment-588984202
|
// https://github.com/mixmark-io/turndown/issues/293#issuecomment-588984202
|
||||||
turndownOpts.blankReplacement = (content: string, node: any) => {
|
turndownOpts.blankReplacement = (content: string, node: any) => {
|
||||||
if (node.matches('object')) {
|
if (node.matches('object')) {
|
||||||
@ -52,7 +52,7 @@ export default class HtmlToMd {
|
|||||||
const pdfRule = {
|
const pdfRule = {
|
||||||
filter: ['embed', 'object'],
|
filter: ['embed', 'object'],
|
||||||
replacement: function(_content: string, node: any, _options: any) {
|
replacement: function(_content: string, node: any, _options: any) {
|
||||||
// We are setting embedded_pdf as name so that we can later distingish them from normal links and create resources for them.
|
// We are setting embedded_pdf as name so that we can later distinguish them from normal links and create resources for them.
|
||||||
if (node.matches('embed') && node.getAttribute('src') && pdfUrlRegex.test(node.getAttribute('src'))) {
|
if (node.matches('embed') && node.getAttribute('src') && pdfUrlRegex.test(node.getAttribute('src'))) {
|
||||||
return `[embedded_pdf](${node.getAttribute('src')})`;
|
return `[embedded_pdf](${node.getAttribute('src')})`;
|
||||||
} else if (node.matches('object') && node.getAttribute('data') && pdfUrlRegex.test(node.getAttribute('data'))) {
|
} else if (node.matches('object') && node.getAttribute('data') && pdfUrlRegex.test(node.getAttribute('data'))) {
|
||||||
|
@ -21,7 +21,7 @@ describe('InMemoryCache', () => {
|
|||||||
it('should expire values', async () => {
|
it('should expire values', async () => {
|
||||||
const cache = new InMemoryCache();
|
const cache = new InMemoryCache();
|
||||||
|
|
||||||
// Check that the value is udefined once the cache has expired
|
// Check that the value is undefined once the cache has expired
|
||||||
cache.setValue('test', 'something', 500);
|
cache.setValue('test', 'something', 500);
|
||||||
expect(cache.value('test')).toBe('something');
|
expect(cache.value('test')).toBe('something');
|
||||||
await time.msleep(510);
|
await time.msleep(510);
|
||||||
|
@ -118,7 +118,7 @@ export default class SyncTargetOneDrive extends BaseSyncTarget {
|
|||||||
|
|
||||||
public async initSynchronizer() {
|
public async initSynchronizer() {
|
||||||
try {
|
try {
|
||||||
if (!(await this.isAuthenticated())) throw new Error('User is not authentified');
|
if (!(await this.isAuthenticated())) throw new Error('User is not authenticated');
|
||||||
return new Synchronizer(this.db(), await this.fileApi(), Setting.value('appType'));
|
return new Synchronizer(this.db(), await this.fileApi(), Setting.value('appType'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
BaseSyncTarget.dispatch({ type: 'SYNC_REPORT_UPDATE', report: { errors: [error] } });
|
BaseSyncTarget.dispatch({ type: 'SYNC_REPORT_UPDATE', report: { errors: [error] } });
|
||||||
|
@ -670,7 +670,7 @@ export default class Synchronizer {
|
|||||||
// up in this place either, because the action
|
// up in this place either, because the action
|
||||||
// cannot be createRemote (because the
|
// cannot be createRemote (because the
|
||||||
// resource has not been created locally) or
|
// resource has not been created locally) or
|
||||||
// updateRemote (because a resouce cannot be
|
// updateRemote (because a resource cannot be
|
||||||
// modified locally unless the blob is present
|
// modified locally unless the blob is present
|
||||||
// too).
|
// too).
|
||||||
//
|
//
|
||||||
@ -1076,7 +1076,7 @@ export default class Synchronizer {
|
|||||||
logger.info(error.message);
|
logger.info(error.message);
|
||||||
|
|
||||||
if (error.code === 'failSafe' || error.code === 'lockError') {
|
if (error.code === 'failSafe' || error.code === 'lockError') {
|
||||||
// Get the message to display on UI, but not in testing to avoid poluting stdout
|
// Get the message to display on UI, but not in testing to avoid polluting stdout
|
||||||
if (!shim.isTestingEnv()) this.progressReport_.errors.push(error.message);
|
if (!shim.isTestingEnv()) this.progressReport_.errors.push(error.message);
|
||||||
this.logLastRequests();
|
this.logLastRequests();
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ export default class TaskQueue {
|
|||||||
|
|
||||||
// In general it's not a big issue if some tasks are still running because
|
// In general it's not a big issue if some tasks are still running because
|
||||||
// it won't call anything unexpected in caller code, since the caller has
|
// it won't call anything unexpected in caller code, since the caller has
|
||||||
// to explicitely retrieve the results
|
// to explicitly retrieve the results
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
while (Object.keys(this.processingTasks_).length) {
|
while (Object.keys(this.processingTasks_).length) {
|
||||||
await time.sleep(0.1);
|
await time.sleep(0.1);
|
||||||
|
@ -58,7 +58,7 @@ class WelcomeUtils {
|
|||||||
const folderAssets = welcomeAssets.folders;
|
const folderAssets = welcomeAssets.folders;
|
||||||
const tempDir = Setting.value('resourceDir');
|
const tempDir = Setting.value('resourceDir');
|
||||||
|
|
||||||
// Actually we don't really support mutiple folders at this point, because not needed
|
// Actually we don't really support multiple folders at this point, because not needed
|
||||||
for (let i = 0; i < folderAssets.length; i++) {
|
for (let i = 0; i < folderAssets.length; i++) {
|
||||||
const folder = await Folder.save({ title: _('Welcome!') });
|
const folder = await Folder.save({ title: _('Welcome!') });
|
||||||
if (!output.defaultFolderId) output.defaultFolderId = folder.id;
|
if (!output.defaultFolderId) output.defaultFolderId = folder.id;
|
||||||
|
@ -232,7 +232,7 @@ export const settingsSections = createSelector(
|
|||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ideallly we would also check if the user was able to synchronize
|
// Ideally we would also check if the user was able to synchronize
|
||||||
// but we don't have a way of doing that besides making a request to Joplin Cloud
|
// but we don't have a way of doing that besides making a request to Joplin Cloud
|
||||||
const syncTargetIsJoplinCloud = settings['sync.target'] === SyncTargetRegistry.nameToId('joplinCloud');
|
const syncTargetIsJoplinCloud = settings['sync.target'] === SyncTargetRegistry.nameToId('joplinCloud');
|
||||||
if (syncTargetIsJoplinCloud) {
|
if (syncTargetIsJoplinCloud) {
|
||||||
|
@ -224,7 +224,7 @@ export default class Database {
|
|||||||
if (type === 'fieldType') {
|
if (type === 'fieldType') {
|
||||||
if (s) s = s.toUpperCase();
|
if (s) s = s.toUpperCase();
|
||||||
if (s === 'INTEGER') s = 'INT';
|
if (s === 'INTEGER') s = 'INT';
|
||||||
if (!(`TYPE_${s}` in this)) throw new Error(`Unkonwn fieldType: ${s}`);
|
if (!(`TYPE_${s}` in this)) throw new Error(`Unknown fieldType: ${s}`);
|
||||||
return (this as any)[`TYPE_${s}`];
|
return (this as any)[`TYPE_${s}`];
|
||||||
}
|
}
|
||||||
if (type === 'syncTarget') {
|
if (type === 'syncTarget') {
|
||||||
|
@ -27,6 +27,7 @@ export const waitForElement = async (parent: any, id: string): Promise<any> => {
|
|||||||
// Imported from https://github.com/Moh-Snoussi/keyboard-event-key-type
|
// Imported from https://github.com/Moh-Snoussi/keyboard-event-key-type
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
// cSpell:disable
|
||||||
type NumericKeypadKeys = 'Decimal' | 'Key11' | 'Key12' | 'Multiply' | 'Add' | 'Clear' | 'Divide' | 'Subtract' | 'Separator' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
|
type NumericKeypadKeys = 'Decimal' | 'Key11' | 'Key12' | 'Multiply' | 'Add' | 'Clear' | 'Divide' | 'Subtract' | 'Separator' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
|
||||||
type UpperAlpha = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
|
type UpperAlpha = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
|
||||||
type LowerAlpha = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';
|
type LowerAlpha = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';
|
||||||
@ -51,3 +52,4 @@ type KoreanKeyboardsOnly = 'HangulMode' | 'HanjaMode' | 'JunjaMode';
|
|||||||
type SpecialValueKey = 'Unidentified';
|
type SpecialValueKey = 'Unidentified';
|
||||||
|
|
||||||
export declare type KeyboardEventKey = SpecialValueKey | ModifierKeys | WhitespaceKeys | NavigationKeys | EditingKeys | UIKeys | DeviceKeys | IMECompositionKeys | LinuxDeadKeys | FunctionKeys | PhoneKeys | MultimediaKeys | TVControlKeys | MediaControllerKeys | SpeechRecognitionKeys | DocumentKeys | ApplicationSelectorKeys | BrowserControlKeys | NumericKeypadKeys | UpperAlpha | LowerAlpha | KoreanKeyboardsOnly;
|
export declare type KeyboardEventKey = SpecialValueKey | ModifierKeys | WhitespaceKeys | NavigationKeys | EditingKeys | UIKeys | DeviceKeys | IMECompositionKeys | LinuxDeadKeys | FunctionKeys | PhoneKeys | MultimediaKeys | TVControlKeys | MediaControllerKeys | SpeechRecognitionKeys | DocumentKeys | ApplicationSelectorKeys | BrowserControlKeys | NumericKeypadKeys | UpperAlpha | LowerAlpha | KoreanKeyboardsOnly;
|
||||||
|
// cSpell:enable
|
||||||
|
@ -58,7 +58,7 @@ function requestCanBeRepeated(error: any) {
|
|||||||
// permission issue, which won't be fixed by repeating the request.
|
// permission issue, which won't be fixed by repeating the request.
|
||||||
if (errorCode === 403 || errorCode === 401) return false;
|
if (errorCode === 403 || errorCode === 401) return false;
|
||||||
|
|
||||||
// The target is explicitely rejecting the item so repeating wouldn't make a difference.
|
// The target is explicitly rejecting the item so repeating wouldn't make a difference.
|
||||||
if (errorCode === 'rejectedByTarget' || errorCode === 'isReadOnly') return false;
|
if (errorCode === 'rejectedByTarget' || errorCode === 'isReadOnly') return false;
|
||||||
|
|
||||||
// We don't repeat failSafe errors because it's an indication of an issue at the
|
// We don't repeat failSafe errors because it's an indication of an issue at the
|
||||||
@ -131,7 +131,7 @@ class FileApi {
|
|||||||
|
|
||||||
// This can be true when the sync target timestamps (updated_time) provided
|
// This can be true when the sync target timestamps (updated_time) provided
|
||||||
// in the delta call are guaranteed to be accurate. That requires
|
// in the delta call are guaranteed to be accurate. That requires
|
||||||
// explicitely setting the timestamp, which is not done anymore on any sync
|
// explicitly setting the timestamp, which is not done anymore on any sync
|
||||||
// target as it wasn't accurate (for example, the file system can't be
|
// target as it wasn't accurate (for example, the file system can't be
|
||||||
// relied on, and even OneDrive for some reason doesn't guarantee that the
|
// relied on, and even OneDrive for some reason doesn't guarantee that the
|
||||||
// timestamp you set is what you get back).
|
// timestamp you set is what you get back).
|
||||||
@ -297,7 +297,7 @@ class FileApi {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprectated
|
// Deprecated
|
||||||
public setTimestamp(path: string, timestampMs: number) {
|
public setTimestamp(path: string, timestampMs: number) {
|
||||||
logger.debug(`setTimestamp ${this.fullPath(path)}`);
|
logger.debug(`setTimestamp ${this.fullPath(path)}`);
|
||||||
return tryAndRepeat(() => this.driver_.setTimestamp(this.fullPath(path), timestampMs), this.requestRepeatCount());
|
return tryAndRepeat(() => this.driver_.setTimestamp(this.fullPath(path), timestampMs), this.requestRepeatCount());
|
||||||
@ -347,13 +347,13 @@ class FileApi {
|
|||||||
return tryAndRepeat(() => this.driver_.delete(this.fullPath(path)), this.requestRepeatCount());
|
return tryAndRepeat(() => this.driver_.delete(this.fullPath(path)), this.requestRepeatCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprectated
|
// Deprecated
|
||||||
public move(oldPath: string, newPath: string) {
|
public move(oldPath: string, newPath: string) {
|
||||||
logger.debug(`move ${this.fullPath(oldPath)} => ${this.fullPath(newPath)}`);
|
logger.debug(`move ${this.fullPath(oldPath)} => ${this.fullPath(newPath)}`);
|
||||||
return tryAndRepeat(() => this.driver_.move(this.fullPath(oldPath), this.fullPath(newPath)), this.requestRepeatCount());
|
return tryAndRepeat(() => this.driver_.move(this.fullPath(oldPath), this.fullPath(newPath)), this.requestRepeatCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprectated
|
// Deprecated
|
||||||
public format() {
|
public format() {
|
||||||
return tryAndRepeat(() => this.driver_.format(), this.requestRepeatCount());
|
return tryAndRepeat(() => this.driver_.format(), this.requestRepeatCount());
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ function enexXmlToHtml_(stream, resources) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the resource does not appear among the note's resources, it
|
// If the resource does not appear among the note's resources, it
|
||||||
// means it's an attachement. It will be appended along with the
|
// means it's an attachment. It will be appended along with the
|
||||||
// other remaining resources at the bottom of the markdown text.
|
// other remaining resources at the bottom of the markdown text.
|
||||||
if (resource && !!resource.id) {
|
if (resource && !!resource.id) {
|
||||||
section.lines = addResourceTag(section.lines, resource, nodeAttributes);
|
section.lines = addResourceTag(section.lines, resource, nodeAttributes);
|
||||||
|
@ -303,8 +303,8 @@ function isWhiteSpace(c: string): boolean {
|
|||||||
return c === '\n' || c === '\r' || c === '\v' || c === '\f' || c === '\t' || c === ' ';
|
return c === '\n' || c === '\r' || c === '\v' || c === '\f' || c === '\t' || c === ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Like QString::simpified(), except that it preserves non-breaking spaces (which
|
// Like QString::simplified(), except that it preserves non-breaking spaces (which
|
||||||
// Evernote uses for identation, etc.)
|
// Evernote uses for indentation, etc.)
|
||||||
function simplifyString(s: string): string {
|
function simplifyString(s: string): string {
|
||||||
let output = '';
|
let output = '';
|
||||||
let previousWhite = false;
|
let previousWhite = false;
|
||||||
@ -905,7 +905,7 @@ function enexXmlToMdArray(stream: any, resources: ResourceEntity[], tasks: Extra
|
|||||||
// <!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export2.dtd">
|
// <!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export2.dtd">
|
||||||
// <en-export export-date="20161221T203133Z" application="Evernote/Windows" version="6.x">
|
// <en-export export-date="20161221T203133Z" application="Evernote/Windows" version="6.x">
|
||||||
// <note>
|
// <note>
|
||||||
// <title>Commande</title>
|
// <title>Command</title>
|
||||||
// <content>
|
// <content>
|
||||||
// <![CDATA[
|
// <![CDATA[
|
||||||
// <?xml version="1.0" encoding="UTF-8"?>
|
// <?xml version="1.0" encoding="UTF-8"?>
|
||||||
@ -951,7 +951,7 @@ function enexXmlToMdArray(stream: any, resources: ResourceEntity[], tasks: Extra
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the resource does not appear among the note's resources, it
|
// If the resource does not appear among the note's resources, it
|
||||||
// means it's an attachement. It will be appended along with the
|
// means it's an attachment. It will be appended along with the
|
||||||
// other remaining resources at the bottom of the markdown text.
|
// other remaining resources at the bottom of the markdown text.
|
||||||
if (resource && !!resource.id) {
|
if (resource && !!resource.id) {
|
||||||
section.lines = addResourceTag(section.lines, `:/${resource.id}`, resource.mime, {
|
section.lines = addResourceTag(section.lines, `:/${resource.id}`, resource.mime, {
|
||||||
@ -1080,7 +1080,7 @@ function enexXmlToMdArray(stream: any, resources: ResourceEntity[], tasks: Extra
|
|||||||
// it's interactive bits) and it's not user-generated content such as a URL that would appear in a comment.
|
// it's interactive bits) and it's not user-generated content such as a URL that would appear in a comment.
|
||||||
// So in this case, we still want to preserve the information but display it in a discreet way as a simple [L].
|
// So in this case, we still want to preserve the information but display it in a discreet way as a simple [L].
|
||||||
|
|
||||||
// Need to pop everything inside the current [] because it can only be special chars that we don't want (they would create uncessary newlines)
|
// Need to pop everything inside the current [] because it can only be special chars that we don't want (they would create unnecessary newlines)
|
||||||
for (let i = section.lines.length - 1; i >= 0; i--) {
|
for (let i = section.lines.length - 1; i >= 0; i--) {
|
||||||
if (section.lines[i] !== '[') {
|
if (section.lines[i] !== '[') {
|
||||||
section.lines.pop();
|
section.lines.pop();
|
||||||
|
@ -631,7 +631,7 @@ export const parsePluralForm = (form: string): ParsePluralFormFunction => {
|
|||||||
'return (plural === true ? 1 : plural ? plural : 0);',
|
'return (plural === true ? 1 : plural ? plural : 0);',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
// eslint-disable-next-line no-new-func -- There's a regex to check the form but it's still slighlty unsafe, eventually we should automatically generate all the functions in advance in build-translations.ts
|
// eslint-disable-next-line no-new-func -- There's a regex to check the form but it's still slightly unsafe, eventually we should automatically generate all the functions in advance in build-translations.ts
|
||||||
return (new Function('n', code)) as ParsePluralFormFunction;
|
return (new Function('n', code)) as ParsePluralFormFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ describe('Should detect list items', () => {
|
|||||||
test('should NOT detect `1)` as empty list item ', () => {
|
test('should NOT detect `1)` as empty list item ', () => {
|
||||||
expect(markdownUtils.isEmptyListItem('1)')).toBe(false);
|
expect(markdownUtils.isEmptyListItem('1)')).toBe(false);
|
||||||
});
|
});
|
||||||
// checbox list
|
// checkbox list
|
||||||
test('should NOT detect `+ [x]` as empty list item ', () => {
|
test('should NOT detect `+ [x]` as empty list item ', () => {
|
||||||
expect(markdownUtils.isEmptyListItem('+ [x]')).toBe(false);
|
expect(markdownUtils.isEmptyListItem('+ [x]')).toBe(false);
|
||||||
});
|
});
|
||||||
|
@ -145,7 +145,7 @@ export default class BaseItem extends BaseModel {
|
|||||||
const ItemClass = this.itemClass(this.modelType());
|
const ItemClass = this.itemClass(this.modelType());
|
||||||
const itemType = ItemClass.modelType();
|
const itemType = ItemClass.modelType();
|
||||||
// The fact that we don't check if the item_id still exist in the corresponding item table, means
|
// The fact that we don't check if the item_id still exist in the corresponding item table, means
|
||||||
// that the returned number might be innaccurate (for example if a sync operation was cancelled)
|
// that the returned number might be inaccurate (for example if a sync operation was cancelled)
|
||||||
const sql = 'SELECT count(*) as total FROM sync_items WHERE sync_target = ? AND item_type = ?';
|
const sql = 'SELECT count(*) as total FROM sync_items WHERE sync_target = ? AND item_type = ?';
|
||||||
const r = await this.db().selectOne(sql, [syncTarget, itemType]);
|
const r = await this.db().selectOne(sql, [syncTarget, itemType]);
|
||||||
return r.total;
|
return r.total;
|
||||||
|
@ -682,7 +682,7 @@ export default class Folder extends BaseItem {
|
|||||||
rootFolders.push(folder);
|
rootFolders.push(folder);
|
||||||
} else {
|
} else {
|
||||||
if (!idToFolders[folder.parent_id]) {
|
if (!idToFolders[folder.parent_id]) {
|
||||||
// It means the notebook is refering a folder that doesn't exist. In theory it shouldn't happen
|
// It means the notebook is referring a folder that doesn't exist. In theory it shouldn't happen
|
||||||
// but sometimes does - https://github.com/laurent22/joplin/issues/1068#issuecomment-450594708
|
// but sometimes does - https://github.com/laurent22/joplin/issues/1068#issuecomment-450594708
|
||||||
rootFolders.push(folder);
|
rootFolders.push(folder);
|
||||||
} else {
|
} else {
|
||||||
|
@ -414,7 +414,7 @@ describe('models/Note', () => {
|
|||||||
expect(movedNote.conflict_original_id).toBe('');
|
expect(movedNote.conflict_original_id).toBe('');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function testResourceReplacment(body: string, pathsToTry: string[], expected: string) {
|
function testResourceReplacement(body: string, pathsToTry: string[], expected: string) {
|
||||||
expect(Note['replaceResourceExternalToInternalLinks_'](pathsToTry, body)).toBe(expected);
|
expect(Note['replaceResourceExternalToInternalLinks_'](pathsToTry, body)).toBe(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,28 +422,28 @@ describe('models/Note', () => {
|
|||||||
const body = '![image.png](file:///C:Users/Username/resources/849eae4dade045298c107fc706b6d2bc.png?t=1655192326803)';
|
const body = '![image.png](file:///C:Users/Username/resources/849eae4dade045298c107fc706b6d2bc.png?t=1655192326803)';
|
||||||
const pathsToTry = ['file:///C:Users/Username/resources'];
|
const pathsToTry = ['file:///C:Users/Username/resources'];
|
||||||
const expected = '![image.png](:/849eae4dade045298c107fc706b6d2bc)';
|
const expected = '![image.png](:/849eae4dade045298c107fc706b6d2bc)';
|
||||||
testResourceReplacment(body, pathsToTry, expected);
|
testResourceReplacement(body, pathsToTry, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('replacement with spaces', () => {
|
test('replacement with spaces', () => {
|
||||||
const body = '![image.png](file:///C:Users/Username%20with%20spaces/resources/849eae4dade045298c107fc706b6d2bc.png?t=1655192326803)';
|
const body = '![image.png](file:///C:Users/Username%20with%20spaces/resources/849eae4dade045298c107fc706b6d2bc.png?t=1655192326803)';
|
||||||
const pathsToTry = ['file:///C:Users/Username with spaces/resources'];
|
const pathsToTry = ['file:///C:Users/Username with spaces/resources'];
|
||||||
const expected = '![image.png](:/849eae4dade045298c107fc706b6d2bc)';
|
const expected = '![image.png](:/849eae4dade045298c107fc706b6d2bc)';
|
||||||
testResourceReplacment(body, pathsToTry, expected);
|
testResourceReplacement(body, pathsToTry, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('replacement with Non-ASCII', () => {
|
test('replacement with Non-ASCII', () => {
|
||||||
const body = '![image.png](file:///C:Users/UsernameWith%C3%A9%C3%A0%C3%B6/resources/849eae4dade045298c107fc706b6d2bc.png?t=1655192326803)';
|
const body = '![image.png](file:///C:Users/UsernameWith%C3%A9%C3%A0%C3%B6/resources/849eae4dade045298c107fc706b6d2bc.png?t=1655192326803)';
|
||||||
const pathsToTry = ['file:///C:Users/UsernameWithéàö/resources'];
|
const pathsToTry = ['file:///C:Users/UsernameWithéàö/resources'];
|
||||||
const expected = '![image.png](:/849eae4dade045298c107fc706b6d2bc)';
|
const expected = '![image.png](:/849eae4dade045298c107fc706b6d2bc)';
|
||||||
testResourceReplacment(body, pathsToTry, expected);
|
testResourceReplacement(body, pathsToTry, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('replacement with Non-ASCII and spaces', () => {
|
test('replacement with Non-ASCII and spaces', () => {
|
||||||
const body = '![image.png](file:///C:Users/Username%20With%20%C3%A9%C3%A0%C3%B6/resources/849eae4dade045298c107fc706b6d2bc.png?t=1655192326803)';
|
const body = '![image.png](file:///C:Users/Username%20With%20%C3%A9%C3%A0%C3%B6/resources/849eae4dade045298c107fc706b6d2bc.png?t=1655192326803)';
|
||||||
const pathsToTry = ['file:///C:Users/Username With éàö/resources'];
|
const pathsToTry = ['file:///C:Users/Username With éàö/resources'];
|
||||||
const expected = '![image.png](:/849eae4dade045298c107fc706b6d2bc)';
|
const expected = '![image.png](:/849eae4dade045298c107fc706b6d2bc)';
|
||||||
testResourceReplacment(body, pathsToTry, expected);
|
testResourceReplacement(body, pathsToTry, expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not allow modifying a read-only note', async () => {
|
it('should not allow modifying a read-only note', async () => {
|
||||||
|
@ -854,7 +854,7 @@ export default class Note extends BaseItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This method will disable the NOTE_UPDATE_ONE action to prevent a lot
|
// This method will disable the NOTE_UPDATE_ONE action to prevent a lot
|
||||||
// of unecessary updates, so it's the caller's responsability to update
|
// of unnecessary updates, so it's the caller's responsibility to update
|
||||||
// the UI once the call is finished. This is done by listening to the
|
// the UI once the call is finished. This is done by listening to the
|
||||||
// NOTE_IS_INSERTING_NOTES action in the application middleware.
|
// NOTE_IS_INSERTING_NOTES action in the application middleware.
|
||||||
public static async insertNotesAt(folderId: string, noteIds: string[], index: number, uncompletedTodosOnTop: boolean, showCompletedTodos: boolean) {
|
public static async insertNotesAt(folderId: string, noteIds: string[], index: number, uncompletedTodosOnTop: boolean, showCompletedTodos: boolean) {
|
||||||
@ -950,19 +950,19 @@ export default class Note extends BaseItem {
|
|||||||
// and the increment between the order values of each inserted notes.
|
// and the increment between the order values of each inserted notes.
|
||||||
let newOrder = 0;
|
let newOrder = 0;
|
||||||
let intervalBetweenNotes = 0;
|
let intervalBetweenNotes = 0;
|
||||||
const defaultIntevalBetweeNotes = 60 * 60 * 1000;
|
const defaultIntevalBetweenNotes = 60 * 60 * 1000;
|
||||||
|
|
||||||
if (!relevantExistingNoteCount) { // If there's no (relevant) notes in the target notebook
|
if (!relevantExistingNoteCount) { // If there's no (relevant) notes in the target notebook
|
||||||
newOrder = Date.now();
|
newOrder = Date.now();
|
||||||
intervalBetweenNotes = defaultIntevalBetweeNotes;
|
intervalBetweenNotes = defaultIntevalBetweenNotes;
|
||||||
} else if (index > lastRelevantNoteIndex) { // Insert at the end (of relevant group)
|
} else if (index > lastRelevantNoteIndex) { // Insert at the end (of relevant group)
|
||||||
intervalBetweenNotes = notes[lastRelevantNoteIndex].order / (noteIds.length + 1);
|
intervalBetweenNotes = notes[lastRelevantNoteIndex].order / (noteIds.length + 1);
|
||||||
newOrder = notes[lastRelevantNoteIndex].order - intervalBetweenNotes;
|
newOrder = notes[lastRelevantNoteIndex].order - intervalBetweenNotes;
|
||||||
} else if (index <= firstRelevantNoteIndex) { // Insert at the beginning (of relevant group)
|
} else if (index <= firstRelevantNoteIndex) { // Insert at the beginning (of relevant group)
|
||||||
const firstNoteOrder = notes[firstRelevantNoteIndex].order;
|
const firstNoteOrder = notes[firstRelevantNoteIndex].order;
|
||||||
if (firstNoteOrder >= Date.now()) {
|
if (firstNoteOrder >= Date.now()) {
|
||||||
intervalBetweenNotes = defaultIntevalBetweeNotes;
|
intervalBetweenNotes = defaultIntevalBetweenNotes;
|
||||||
newOrder = firstNoteOrder + defaultIntevalBetweeNotes;
|
newOrder = firstNoteOrder + defaultIntevalBetweenNotes;
|
||||||
} else {
|
} else {
|
||||||
intervalBetweenNotes = (Date.now() - firstNoteOrder) / (noteIds.length + 1);
|
intervalBetweenNotes = (Date.now() - firstNoteOrder) / (noteIds.length + 1);
|
||||||
newOrder = firstNoteOrder + intervalBetweenNotes * noteIds.length;
|
newOrder = firstNoteOrder + intervalBetweenNotes * noteIds.length;
|
||||||
@ -976,7 +976,7 @@ export default class Note extends BaseItem {
|
|||||||
for (let i = index; i >= 0; i--) {
|
for (let i = index; i >= 0; i--) {
|
||||||
const n = notes[i];
|
const n = notes[i];
|
||||||
if (n.order <= previousOrder) {
|
if (n.order <= previousOrder) {
|
||||||
const o = previousOrder + defaultIntevalBetweeNotes;
|
const o = previousOrder + defaultIntevalBetweenNotes;
|
||||||
const updatedNote = await this.updateNoteOrder_(n, o);
|
const updatedNote = await this.updateNoteOrder_(n, o);
|
||||||
notes[i] = { ...n, ...updatedNote };
|
notes[i] = { ...n, ...updatedNote };
|
||||||
previousOrder = o;
|
previousOrder = o;
|
||||||
|
@ -5,7 +5,7 @@ import { LoadOptions } from './utils/types';
|
|||||||
|
|
||||||
// - If is_associated = 1, note_resources indicates which note_id is currently associated with the given resource_id
|
// - If is_associated = 1, note_resources indicates which note_id is currently associated with the given resource_id
|
||||||
// - If is_associated = 0, note_resources indicates which note_id *was* associated with the given resource_id
|
// - If is_associated = 0, note_resources indicates which note_id *was* associated with the given resource_id
|
||||||
// - last_seen_time tells the last time that reosurce was associated with this note.
|
// - last_seen_time tells the last time that resource was associated with this note.
|
||||||
// - If last_seen_time is 0, it means the resource has never been associated with any note.
|
// - If last_seen_time is 0, it means the resource has never been associated with any note.
|
||||||
|
|
||||||
export default class NoteResource extends BaseModel {
|
export default class NoteResource extends BaseModel {
|
||||||
@ -134,7 +134,7 @@ export default class NoteResource extends BaseModel {
|
|||||||
// If the resource is not associated with any note, and has never
|
// If the resource is not associated with any note, and has never
|
||||||
// been synced, it means it's a local resource that was removed from
|
// been synced, it means it's a local resource that was removed from
|
||||||
// a note (or the note was deleted). In which case, we set a
|
// a note (or the note was deleted). In which case, we set a
|
||||||
// "last_seen_time", so that it can be considered an orphan reosurce
|
// "last_seen_time", so that it can be considered an orphan resource
|
||||||
// that can be auto-deleted.
|
// that can be auto-deleted.
|
||||||
//
|
//
|
||||||
// https://github.com/laurent22/joplin/issues/932#issuecomment-933736405
|
// https://github.com/laurent22/joplin/issues/932#issuecomment-933736405
|
||||||
|
@ -204,6 +204,7 @@ describe('models/Revision', () => {
|
|||||||
expect(newRevs[2].id).toBe('789');
|
expect(newRevs[2].id).toBe('789');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// cSpell:disable
|
||||||
it('should create patch stats', (async () => {
|
it('should create patch stats', (async () => {
|
||||||
const tests = [
|
const tests = [
|
||||||
{
|
{
|
||||||
@ -240,5 +241,6 @@ describe('models/Revision', () => {
|
|||||||
expect(stats.added).toBe(test.expected[1]);
|
expect(stats.added).toBe(test.expected[1]);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
// cSpell:enable
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -202,7 +202,7 @@ export const MAX_HISTORY = 200;
|
|||||||
const derivedStateCache_: any = {};
|
const derivedStateCache_: any = {};
|
||||||
|
|
||||||
// Allows, for a given state, to return the same derived
|
// Allows, for a given state, to return the same derived
|
||||||
// objects, to prevent unecessary updates on calling components.
|
// objects, to prevent unnecessary updates on calling components.
|
||||||
const cacheEnabledOutput = (key: string, output: any) => {
|
const cacheEnabledOutput = (key: string, output: any) => {
|
||||||
key = `${key}_${JSON.stringify(output)}`;
|
key = `${key}_${JSON.stringify(output)}`;
|
||||||
if (derivedStateCache_[key]) return derivedStateCache_[key];
|
if (derivedStateCache_[key]) return derivedStateCache_[key];
|
||||||
|
@ -170,7 +170,7 @@ export default class DecryptionWorker {
|
|||||||
this.dispatchReport({ state: 'started' });
|
this.dispatchReport({ state: 'started' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const notLoadedMasterKeyDisptaches = [];
|
const notLoadedMasterKeyDispatches = [];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const result: ItemsThatNeedDecryptionResult = await BaseItem.itemsThatNeedDecryption(excludedIds);
|
const result: ItemsThatNeedDecryptionResult = await BaseItem.itemsThatNeedDecryption(excludedIds);
|
||||||
@ -230,12 +230,12 @@ export default class DecryptionWorker {
|
|||||||
excludedIds.push(item.id);
|
excludedIds.push(item.id);
|
||||||
|
|
||||||
if (error.code === 'masterKeyNotLoaded' && options.masterKeyNotLoadedHandler === 'dispatch') {
|
if (error.code === 'masterKeyNotLoaded' && options.masterKeyNotLoadedHandler === 'dispatch') {
|
||||||
if (notLoadedMasterKeyDisptaches.indexOf(error.masterKeyId) < 0) {
|
if (notLoadedMasterKeyDispatches.indexOf(error.masterKeyId) < 0) {
|
||||||
this.dispatch({
|
this.dispatch({
|
||||||
type: 'MASTERKEY_ADD_NOT_LOADED',
|
type: 'MASTERKEY_ADD_NOT_LOADED',
|
||||||
id: error.masterKeyId,
|
id: error.masterKeyId,
|
||||||
});
|
});
|
||||||
notLoadedMasterKeyDisptaches.push(error.masterKeyId);
|
notLoadedMasterKeyDispatches.push(error.masterKeyId);
|
||||||
}
|
}
|
||||||
await clearDecryptionCounter();
|
await clearDecryptionCounter();
|
||||||
continue;
|
continue;
|
||||||
|
@ -267,7 +267,7 @@ export default class KeymapService extends BaseService {
|
|||||||
this.defaultKeymapItems.forEach(({ command, accelerator }) => {
|
this.defaultKeymapItems.forEach(({ command, accelerator }) => {
|
||||||
const currentAccelerator = this.getAccelerator(command);
|
const currentAccelerator = this.getAccelerator(command);
|
||||||
|
|
||||||
// Only the customized/changed keymap items are neccessary for the custom keymap
|
// Only the customized/changed keymap items are necessary for the custom keymap
|
||||||
// Customizations can be merged with the original keymap at the runtime
|
// Customizations can be merged with the original keymap at the runtime
|
||||||
if (this.getAccelerator(command) !== accelerator) {
|
if (this.getAccelerator(command) !== accelerator) {
|
||||||
customkeymapItems.push({ command, accelerator: currentAccelerator });
|
customkeymapItems.push({ command, accelerator: currentAccelerator });
|
||||||
|
@ -21,13 +21,13 @@ enum ReportItemType {
|
|||||||
CloseList = 'closeList',
|
CloseList = 'closeList',
|
||||||
}
|
}
|
||||||
|
|
||||||
type RerportItemOrString = ReportItem | string;
|
type ReportItemOrString = ReportItem | string;
|
||||||
|
|
||||||
export type RetryAllHandler = ()=> void;
|
export type RetryAllHandler = ()=> void;
|
||||||
|
|
||||||
export interface ReportSection {
|
export interface ReportSection {
|
||||||
title: string;
|
title: string;
|
||||||
body: RerportItemOrString[];
|
body: ReportItemOrString[];
|
||||||
name?: string;
|
name?: string;
|
||||||
canRetryAll?: boolean;
|
canRetryAll?: boolean;
|
||||||
retryAllHandler?: RetryAllHandler;
|
retryAllHandler?: RetryAllHandler;
|
||||||
@ -149,7 +149,7 @@ export default class ReportService {
|
|||||||
const retryHandlers: Function[] = [];
|
const retryHandlers: Function[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < section.body.length; i++) {
|
for (let i = 0; i < section.body.length; i++) {
|
||||||
const item: RerportItemOrString = section.body[i];
|
const item: ReportItemOrString = section.body[i];
|
||||||
if (typeof item !== 'string' && item.canRetry) {
|
if (typeof item !== 'string' && item.canRetry) {
|
||||||
retryHandlers.push(item.retryHandler);
|
retryHandlers.push(item.retryHandler);
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ export default class ResourceEditWatcher {
|
|||||||
//
|
//
|
||||||
// We also need this because some events are handled twice - once in the "all" event
|
// We also need this because some events are handled twice - once in the "all" event
|
||||||
// handle and once in the "raw" event handler, due to a bug in chokidar. So having
|
// handle and once in the "raw" event handler, due to a bug in chokidar. So having
|
||||||
// this check means we don't unecessarily save the resource twice when the file is
|
// this check means we don't unnecessarily save the resource twice when the file is
|
||||||
// modified by the user.
|
// modified by the user.
|
||||||
this.logger().debug(`ResourceEditWatcher: No timestamp and file size change - skip: ${resourceId}`);
|
this.logger().debug(`ResourceEditWatcher: No timestamp and file size change - skip: ${resourceId}`);
|
||||||
return;
|
return;
|
||||||
|
@ -236,11 +236,11 @@ describe('services/ResourceService', () => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// it('should auto-delete resource even if the associated note was deleted immediately', (async () => {
|
// it('should auto-delete resource even if the associated note was deleted immediately', (async () => {
|
||||||
// // Previoulsy, when a resource was be attached to a note, then the
|
// // Previously, when a resource was be attached to a note, then the
|
||||||
// // note was immediately deleted, the ResourceService would not have
|
// // note was immediately deleted, the ResourceService would not have
|
||||||
// // time to quick in an index the resource/note relation. It means
|
// // time to quick in an index the resource/note relation. It means
|
||||||
// // that when doing the orphan resource deletion job, those
|
// // that when doing the orphan resource deletion job, those
|
||||||
// // resources would permanently stay behing.
|
// // resources would permanently stay behind.
|
||||||
// // https://github.com/laurent22/joplin/issues/932
|
// // https://github.com/laurent22/joplin/issues/932
|
||||||
|
|
||||||
// const service = new ResourceService();
|
// const service = new ResourceService();
|
||||||
|
@ -257,7 +257,7 @@ describe('services/RevisionService', () => {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should create a revision for notes that get deleted (recyle bin)', (async () => {
|
it('should create a revision for notes that get deleted (recycle bin)', (async () => {
|
||||||
const n1 = await Note.save({ title: 'hello' });
|
const n1 = await Note.save({ title: 'hello' });
|
||||||
const noteId = n1.id;
|
const noteId = n1.id;
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -7,7 +7,7 @@ interface TestData {
|
|||||||
ciphertext: string;
|
ciphertext: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is conveninent to quickly generate some data to verify for example that
|
// This is convenient to quickly generate some data to verify for example that
|
||||||
// react-native-rsa can decrypt data from node-rsa and vice-versa.
|
// react-native-rsa can decrypt data from node-rsa and vice-versa.
|
||||||
export async function createTestData() {
|
export async function createTestData() {
|
||||||
const plaintext = 'just testing';
|
const plaintext = 'just testing';
|
||||||
@ -84,6 +84,8 @@ export async function checkTestData(data: TestData, options: CheckTestDataOption
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cSpell:disable
|
||||||
|
|
||||||
// Data generated on mobile using react-native-rsa-native
|
// Data generated on mobile using react-native-rsa-native
|
||||||
const mobileData = {
|
const mobileData = {
|
||||||
'publicKey': '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlEVSnwMpmGC+YaRw3B37BP1IBth02OFCrlZjlkn14OijnmQaOKGxhJtthvlVVEOEc50D+MMKZ1mJleER4FnD3CoGHaVZmZRa3wnuTblctF/in0mgywFJ6HlEXngUrWt2TkCnkwg4nP0IKlQ4URBxWGllVbWUgqUs5uAtV4mkrx+Ke68j+suoN8w5BF9WnYJCclDCplUOFx77llw1Z/7O8UjkgbfYKOnwMEpxlO1SVutNQNgD4BOtGn73ai0qjHKq5as8SKJb/ch+uAX95bJHlOOvBrHw718gcbnxkn6PEN3vl4/HbmHFj/V4zxG8ZF82+oTOh6m/HGdPPLpF8e98dQIDAQAB\n-----END PUBLIC KEY-----',
|
'publicKey': '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlEVSnwMpmGC+YaRw3B37BP1IBth02OFCrlZjlkn14OijnmQaOKGxhJtthvlVVEOEc50D+MMKZ1mJleER4FnD3CoGHaVZmZRa3wnuTblctF/in0mgywFJ6HlEXngUrWt2TkCnkwg4nP0IKlQ4URBxWGllVbWUgqUs5uAtV4mkrx+Ke68j+suoN8w5BF9WnYJCclDCplUOFx77llw1Z/7O8UjkgbfYKOnwMEpxlO1SVutNQNgD4BOtGn73ai0qjHKq5as8SKJb/ch+uAX95bJHlOOvBrHw718gcbnxkn6PEN3vl4/HbmHFj/V4zxG8ZF82+oTOh6m/HGdPPLpF8e98dQIDAQAB\n-----END PUBLIC KEY-----',
|
||||||
@ -100,6 +102,8 @@ const desktopData = {
|
|||||||
'ciphertext': 'PRqiQjxnQMukoYPA9XtlGcgAjwuDJd24GtJ3iO2qhh0HnbPnx3c8ZaGWJyV1ejZCwIWv509js7sCTHtXqeGkZr//Db6oOIyi77VzRwvzPxReHPefF0rX62uMh+zTmQW7KSrFeAvtnpWiDcyynUtwycgrZcQCHZoEmSSyc3cyj09HgqEoSQb0BOc8daR0aXwOpgXsB8ypf3+m23U1gZmIyl0glymTN9h1jopV9dRtw5ufcc4ve/hHKp0gbaT2OaRKOLr6AXmbDGwkF5bsvjV+v4tTkj96OUjoG9qUMQh/JYRMl7mxJriUB3Jc6WHEKRVPQYAIZODfEOy3rkHwWAcYjA==',
|
'ciphertext': 'PRqiQjxnQMukoYPA9XtlGcgAjwuDJd24GtJ3iO2qhh0HnbPnx3c8ZaGWJyV1ejZCwIWv509js7sCTHtXqeGkZr//Db6oOIyi77VzRwvzPxReHPefF0rX62uMh+zTmQW7KSrFeAvtnpWiDcyynUtwycgrZcQCHZoEmSSyc3cyj09HgqEoSQb0BOc8daR0aXwOpgXsB8ypf3+m23U1gZmIyl0glymTN9h1jopV9dRtw5ufcc4ve/hHKp0gbaT2OaRKOLr6AXmbDGwkF5bsvjV+v4tTkj96OUjoG9qUMQh/JYRMl7mxJriUB3Jc6WHEKRVPQYAIZODfEOy3rkHwWAcYjA==',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// cSpell:enable
|
||||||
|
|
||||||
// This can be used to run integration tests directly on device. It will throw
|
// This can be used to run integration tests directly on device. It will throw
|
||||||
// an error if something cannot be decrypted, or else print info messages.
|
// an error if something cannot be decrypted, or else print info messages.
|
||||||
export const runIntegrationTests = async (silent = false) => {
|
export const runIntegrationTests = async (silent = false) => {
|
||||||
|
@ -36,7 +36,7 @@ export async function setupAndEnableEncryption(service: EncryptionService, maste
|
|||||||
|
|
||||||
export async function setupAndDisableEncryption(service: EncryptionService) {
|
export async function setupAndDisableEncryption(service: EncryptionService) {
|
||||||
// Allow disabling encryption even if some items are still encrypted, because whether E2EE is enabled or disabled
|
// Allow disabling encryption even if some items are still encrypted, because whether E2EE is enabled or disabled
|
||||||
// should not affect whether items will enventually be decrypted or not (DecryptionWorker will still work as
|
// should not affect whether items will eventually be decrypted or not (DecryptionWorker will still work as
|
||||||
// long as there are encrypted items). Also even if decryption is disabled, it's possible that encrypted items
|
// long as there are encrypted items). Also even if decryption is disabled, it's possible that encrypted items
|
||||||
// will still be received via synchronisation.
|
// will still be received via synchronisation.
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ export async function migrateMasterPassword() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// All master keys normally should be decryped with the master password, however
|
// All master keys normally should be decrypted with the master password, however
|
||||||
// previously any master key could be encrypted with any password, so to support
|
// previously any master key could be encrypted with any password, so to support
|
||||||
// this legacy case, we first check if the MK decrypts with the master password.
|
// this legacy case, we first check if the MK decrypts with the master password.
|
||||||
// If not, try with the master key specific password, if any is defined.
|
// If not, try with the master key specific password, if any is defined.
|
||||||
|
@ -189,7 +189,7 @@ export default class InteropService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the module that matches the given type ("importer" or "exporter")
|
// Find the module that matches the given type ("importer" or "exporter")
|
||||||
// and the given format. Some formats can have multiple assocated importers
|
// and the given format. Some formats can have multiple associated importers
|
||||||
// or exporters, such as ENEX. In this case, the one marked as "isDefault"
|
// or exporters, such as ENEX. In this case, the one marked as "isDefault"
|
||||||
// is returned. This is useful to auto-detect the module based on the format.
|
// is returned. This is useful to auto-detect the module based on the format.
|
||||||
// For more precise matching, newModuleFromPath_ should be used.
|
// For more precise matching, newModuleFromPath_ should be used.
|
||||||
|
@ -39,7 +39,7 @@ export default class InteropService_Exporter_Md extends InteropService_Exporter_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async relaceLinkedItemIdsByRelativePaths_(item: any) {
|
private async replaceLinkedItemIdsByRelativePaths_(item: any) {
|
||||||
const relativePathToRoot = await this.makeDirPath_(item, '..');
|
const relativePathToRoot = await this.makeDirPath_(item, '..');
|
||||||
|
|
||||||
const newBody = await this.replaceResourceIdsByRelativePaths_(item.body, relativePathToRoot);
|
const newBody = await this.replaceResourceIdsByRelativePaths_(item.body, relativePathToRoot);
|
||||||
@ -130,7 +130,7 @@ export default class InteropService_Exporter_Md extends InteropService_Exporter_
|
|||||||
const notePaths = this.context() && this.context().notePaths ? this.context().notePaths : {};
|
const notePaths = this.context() && this.context().notePaths ? this.context().notePaths : {};
|
||||||
const noteFilePath = `${this.destDir_}/${notePaths[item.id]}`;
|
const noteFilePath = `${this.destDir_}/${notePaths[item.id]}`;
|
||||||
|
|
||||||
const noteBody = await this.relaceLinkedItemIdsByRelativePaths_(item);
|
const noteBody = await this.replaceLinkedItemIdsByRelativePaths_(item);
|
||||||
const modNote = { ...item, body: noteBody };
|
const modNote = { ...item, body: noteBody };
|
||||||
const noteContent = await this.getNoteExportContent_(modNote);
|
const noteContent = await this.getNoteExportContent_(modNote);
|
||||||
await shim.fsDriver().mkdir(dirname(noteFilePath));
|
await shim.fsDriver().mkdir(dirname(noteFilePath));
|
||||||
|
@ -99,7 +99,7 @@ export default class InteropService_Exporter_Md_frontmatter extends InteropServi
|
|||||||
|
|
||||||
private extractMetadata(note: NoteEntity) {
|
private extractMetadata(note: NoteEntity) {
|
||||||
const md: MdFrontMatterExport = {};
|
const md: MdFrontMatterExport = {};
|
||||||
// Every variable needs to be converted seperately, so they will be handles in groups
|
// Every variable needs to be converted separately, so they will be handles in groups
|
||||||
//
|
//
|
||||||
// title
|
// title
|
||||||
if (note.title) { md['title'] = note.title; }
|
if (note.title) { md['title'] = note.title; }
|
||||||
|
@ -140,7 +140,7 @@ export default class InteropService_Importer_Md extends InteropService_Importer_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The first is a normal link, the second is supports the <link> and [](<link with spaces>) syntax
|
// The first is a normal link, the second is supports the <link> and [](<link with spaces>) syntax
|
||||||
// Only opening patterns are consider in order to cover all occurances
|
// Only opening patterns are consider in order to cover all occurrences
|
||||||
// We need to use the encoded link as well because some links (link's with spaces)
|
// We need to use the encoded link as well because some links (link's with spaces)
|
||||||
// will appear encoded in the source. Other links (unicode chars) will not
|
// will appear encoded in the source. Other links (unicode chars) will not
|
||||||
const linksToReplace = [this.trimAnchorLink(link), this.trimAnchorLink(encodedLink)];
|
const linksToReplace = [this.trimAnchorLink(link), this.trimAnchorLink(encodedLink)];
|
||||||
|
@ -171,7 +171,9 @@ describe('InteropService_Importer_Md_frontmatter: importMetadata', () => {
|
|||||||
|
|
||||||
it('should import a note that contains an image in DataUrl format', async () => {
|
it('should import a note that contains an image in DataUrl format', async () => {
|
||||||
const note = await importTestFile('note_with_dataurl_image.md');
|
const note = await importTestFile('note_with_dataurl_image.md');
|
||||||
|
// cSpell:disable
|
||||||
expect(note.body).toBe('<img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2023%2038%22%3E%3Cpath%20d%3D%22M16.6%2038.1h-5.5l-.2-2.9-.2%202.9h-5.5L5%2025.3l-.8%202a1.53%201.53%200%2001-1.9.9l-1.2-.4a1.58%201.58%200%2001-1-1.9v-.1c.3-.9%203.1-11.2%203.1-11.2a2.66%202.66%200%20012.3-2l.6-.5a6.93%206.93%200%20014.7-12%206.8%206.8%200%20014.9%202%207%207%200%20012%204.9%206.65%206.65%200%2001-2.2%205l.7.5a2.78%202.78%200%20012.4%202s2.9%2011.2%202.9%2011.3a1.53%201.53%200%2001-.9%201.9l-1.3.4a1.63%201.63%200%2001-1.9-.9l-.7-1.8-.1%2012.7zm-3.6-2h1.7L14.9%2020.3l1.9-.3%202.4%206.3.3-.1c-.2-.8-.8-3.2-2.8-10.9a.63.63%200%2000-.6-.5h-.6l-1.1-.9h-1.9l-.3-2a4.83%204.83%200%20003.5-4.7A4.78%204.78%200%200011%202.3H10.8a4.9%204.9%200%2000-1.4%209.6l-.3%202h-1.9l-1%20.9h-.6a.74.74%200%2000-.6.5c-2%207.5-2.7%2010-3%2010.9l.3.1L4.8%2020l1.9.3.2%2015.8h1.6l.6-8.4a1.52%201.52%200%20011.5-1.4%201.5%201.5%200%20011.5%201.4l.9%208.4zm-10.9-9.6zm17.5-.1z%22%20style%3D%22isolation%3Aisolate%22%20fill%3D%22%23333%22%20opacity%3D%22.7%22/%3E%3Cpath%20d%3D%22M5.9%2013.6l1.1-.9h7.8l1.2.9%22%20fill%3D%22%23ce592c%22/%3E%3Cellipse%20cx%3D%2210.9%22%20cy%3D%2213.1%22%20rx%3D%222.7%22%20ry%3D%22.3%22%20style%3D%22isolation%3Aisolate%22%20fill%3D%22%23ce592c%22%20opacity%3D%22.5%22/%3E%3Cpath%20d%3D%22M20.6%2026.1l-2.9-11.3a1.71%201.71%200%2000-1.6-1.2H5.699999999999999a1.69%201.69%200%2000-1.5%201.3l-3.1%2011.3a.61.61%200%2000.3.7l1.1.4a.61.61%200%2000.7-.3l2.7-6.7.2%2016.8h3.6l.6-9.3a.47.47%200%2001.44-.5h.06c.4%200%20.4.2.5.5l.6%209.3h3.6L15.7%2020.3l2.5%206.6a.52.52%200%2000.66.31l1.2-.4a.57.57%200%2000.5-.7z%22%20fill%3D%22%23fdbf2d%22/%3E%3Cpath%20d%3D%22M7%2013.6l3.9%206.7%203.9-6.7%22%20style%3D%22isolation%3Aisolate%22%20fill%3D%22%23cf572e%22%20opacity%3D%22.6%22/%3E%3Ccircle%20cx%3D%2210.9%22%20cy%3D%227%22%20r%3D%225.9%22%20fill%3D%22%23fdbf2d%22/%3E%3C/svg%3E" alt="Street View Pegman Control" style="height:30px;width:30px;position:absolute;transform:translate(-50%,-50%);pointer-events:none">');
|
expect(note.body).toBe('<img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2023%2038%22%3E%3Cpath%20d%3D%22M16.6%2038.1h-5.5l-.2-2.9-.2%202.9h-5.5L5%2025.3l-.8%202a1.53%201.53%200%2001-1.9.9l-1.2-.4a1.58%201.58%200%2001-1-1.9v-.1c.3-.9%203.1-11.2%203.1-11.2a2.66%202.66%200%20012.3-2l.6-.5a6.93%206.93%200%20014.7-12%206.8%206.8%200%20014.9%202%207%207%200%20012%204.9%206.65%206.65%200%2001-2.2%205l.7.5a2.78%202.78%200%20012.4%202s2.9%2011.2%202.9%2011.3a1.53%201.53%200%2001-.9%201.9l-1.3.4a1.63%201.63%200%2001-1.9-.9l-.7-1.8-.1%2012.7zm-3.6-2h1.7L14.9%2020.3l1.9-.3%202.4%206.3.3-.1c-.2-.8-.8-3.2-2.8-10.9a.63.63%200%2000-.6-.5h-.6l-1.1-.9h-1.9l-.3-2a4.83%204.83%200%20003.5-4.7A4.78%204.78%200%200011%202.3H10.8a4.9%204.9%200%2000-1.4%209.6l-.3%202h-1.9l-1%20.9h-.6a.74.74%200%2000-.6.5c-2%207.5-2.7%2010-3%2010.9l.3.1L4.8%2020l1.9.3.2%2015.8h1.6l.6-8.4a1.52%201.52%200%20011.5-1.4%201.5%201.5%200%20011.5%201.4l.9%208.4zm-10.9-9.6zm17.5-.1z%22%20style%3D%22isolation%3Aisolate%22%20fill%3D%22%23333%22%20opacity%3D%22.7%22/%3E%3Cpath%20d%3D%22M5.9%2013.6l1.1-.9h7.8l1.2.9%22%20fill%3D%22%23ce592c%22/%3E%3Cellipse%20cx%3D%2210.9%22%20cy%3D%2213.1%22%20rx%3D%222.7%22%20ry%3D%22.3%22%20style%3D%22isolation%3Aisolate%22%20fill%3D%22%23ce592c%22%20opacity%3D%22.5%22/%3E%3Cpath%20d%3D%22M20.6%2026.1l-2.9-11.3a1.71%201.71%200%2000-1.6-1.2H5.699999999999999a1.69%201.69%200%2000-1.5%201.3l-3.1%2011.3a.61.61%200%2000.3.7l1.1.4a.61.61%200%2000.7-.3l2.7-6.7.2%2016.8h3.6l.6-9.3a.47.47%200%2001.44-.5h.06c.4%200%20.4.2.5.5l.6%209.3h3.6L15.7%2020.3l2.5%206.6a.52.52%200%2000.66.31l1.2-.4a.57.57%200%2000.5-.7z%22%20fill%3D%22%23fdbf2d%22/%3E%3Cpath%20d%3D%22M7%2013.6l3.9%206.7%203.9-6.7%22%20style%3D%22isolation%3Aisolate%22%20fill%3D%22%23cf572e%22%20opacity%3D%22.6%22/%3E%3Ccircle%20cx%3D%2210.9%22%20cy%3D%227%22%20r%3D%225.9%22%20fill%3D%22%23fdbf2d%22/%3E%3C/svg%3E" alt="Street View Pegman Control" style="height:30px;width:30px;position:absolute;transform:translate(-50%,-50%);pointer-events:none">');
|
||||||
|
// cSpell:enable
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should recognize frontmatter in a file that starts with a UTF8 byte order mark', async () => {
|
it('should recognize frontmatter in a file that starts with a UTF8 byte order mark', async () => {
|
||||||
|
@ -28,7 +28,7 @@ function normalizeYamlWhitespace(yaml: string[]): string[] {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a helper functon to convert an arbitrary author variable into a string
|
// This is a helper function to convert an arbitrary author variable into a string
|
||||||
// the use case is for loading from r-markdown/pandoc style notes
|
// the use case is for loading from r-markdown/pandoc style notes
|
||||||
// references:
|
// references:
|
||||||
// https://pandoc.org/MANUAL.html#extension-yaml_metadata_block
|
// https://pandoc.org/MANUAL.html#extension-yaml_metadata_block
|
||||||
@ -143,7 +143,7 @@ export default class InteropService_Importer_Md_frontmatter extends InteropServi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tags are handled seperately from typical metadata
|
// Tags are handled separately from typical metadata
|
||||||
let tags: string[] = [];
|
let tags: string[] = [];
|
||||||
if ('tags' in md) {
|
if ('tags' in md) {
|
||||||
// Only create unique tags
|
// Only create unique tags
|
||||||
|
@ -161,7 +161,7 @@ describe('OcrService', () => {
|
|||||||
|
|
||||||
const service = newOcrService();
|
const service = newOcrService();
|
||||||
|
|
||||||
// The service will print a warnign so we disable it in tests
|
// The service will print a warning so we disable it in tests
|
||||||
Logger.globalLogger.enabled = false;
|
Logger.globalLogger.enabled = false;
|
||||||
await service.processResources();
|
await service.processResources();
|
||||||
Logger.globalLogger.enabled = true;
|
Logger.globalLogger.enabled = true;
|
||||||
@ -210,7 +210,7 @@ describe('OcrService', () => {
|
|||||||
const service2 = newOcrService();
|
const service2 = newOcrService();
|
||||||
await service2.processResources();
|
await service2.processResources();
|
||||||
await synchronizerStart();
|
await synchronizerStart();
|
||||||
const expectedResouceUpatedTime = (await Resource.all())[0].updated_time;
|
const expectedResourceUpdatedTime = (await Resource.all())[0].updated_time;
|
||||||
|
|
||||||
await switchClient(1);
|
await switchClient(1);
|
||||||
|
|
||||||
@ -226,7 +226,7 @@ describe('OcrService', () => {
|
|||||||
expect(resource.ocr_text).toBe('Dummy PDF file');
|
expect(resource.ocr_text).toBe('Dummy PDF file');
|
||||||
expect(resource.ocr_error).toBe('');
|
expect(resource.ocr_error).toBe('');
|
||||||
expect(resource.ocr_status).toBe(ResourceOcrStatus.Done);
|
expect(resource.ocr_status).toBe(ResourceOcrStatus.Done);
|
||||||
expect(resource.updated_time).toBe(expectedResouceUpatedTime);
|
expect(resource.updated_time).toBe(expectedResourceUpdatedTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
await service1.dispose();
|
await service1.dispose();
|
||||||
|
@ -20,7 +20,7 @@ import { Path } from './types';
|
|||||||
* In general you would use the methods in this class as if you were using a REST API. There are four methods that map to GET, POST, PUT and DELETE calls.
|
* In general you would use the methods in this class as if you were using a REST API. There are four methods that map to GET, POST, PUT and DELETE calls.
|
||||||
* And each method takes these parameters:
|
* And each method takes these parameters:
|
||||||
*
|
*
|
||||||
* * `path`: This is an array that represents the path to the resource in the form `["resouceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
|
* * `path`: This is an array that represents the path to the resource in the form `["resourceName", "resourceId", "resourceLink"]` (eg. ["tags", ":id", "notes"]). The "resources" segment is the name of the resources you want to access (eg. "notes", "folders", etc.). If not followed by anything, it will refer to all the resources in that collection. The optional "resourceId" points to a particular resources within the collection. Finally, an optional "link" can be present, which links the resource to a collection of resources. This can be used in the API for example to retrieve all the notes associated with a tag.
|
||||||
* * `query`: (Optional) The query parameters. In a URL, this is the part after the question mark "?". In this case, it should be an object with key/value pairs.
|
* * `query`: (Optional) The query parameters. In a URL, this is the part after the question mark "?". In this case, it should be an object with key/value pairs.
|
||||||
* * `data`: (Optional) Applies to PUT and POST calls only. The request body contains the data you want to create or modify, for example the content of a note or folder.
|
* * `data`: (Optional) Applies to PUT and POST calls only. The request body contains the data you want to create or modify, for example the content of a note or folder.
|
||||||
* * `files`: (Optional) Used to create new resources and associate them with files.
|
* * `files`: (Optional) Used to create new resources and associate them with files.
|
||||||
|
@ -101,9 +101,9 @@ export default class JoplinImaging {
|
|||||||
return this.cacheImage(resizedImage);
|
return this.cacheImage(resizedImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async crop(handle: Handle, rectange: Rectangle) {
|
public async crop(handle: Handle, rectangle: Rectangle) {
|
||||||
const image = this.imageByHandle(handle);
|
const image = this.imageByHandle(handle);
|
||||||
const croppedImage = image.data.crop(rectange);
|
const croppedImage = image.data.crop(rectangle);
|
||||||
return this.cacheImage(croppedImage);
|
return this.cacheImage(croppedImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ export interface ListRenderer {
|
|||||||
/**
|
/**
|
||||||
* The size of each item must be specified in advance for performance
|
* The size of each item must be specified in advance for performance
|
||||||
* reasons, and cannot be changed afterwards. If the item flow is top to
|
* reasons, and cannot be changed afterwards. If the item flow is top to
|
||||||
* bottom, you only need to specificy the item height (the width will be
|
* bottom, you only need to specify the item height (the width will be
|
||||||
* ignored).
|
* ignored).
|
||||||
*/
|
*/
|
||||||
itemSize: Size;
|
itemSize: Size;
|
||||||
@ -155,7 +155,7 @@ export interface ListRenderer {
|
|||||||
onRenderNote: OnRenderNoteHandler;
|
onRenderNote: OnRenderNoteHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This handler allows adding some interacivity to the note renderer -
|
* This handler allows adding some interactivity to the note renderer -
|
||||||
* whenever an input element within the item is changed (for example, when a
|
* whenever an input element within the item is changed (for example, when a
|
||||||
* checkbox is clicked, or a text input is changed), this `onChange` handler
|
* checkbox is clicked, or a text input is changed), this `onChange` handler
|
||||||
* is going to be called.
|
* is going to be called.
|
||||||
|
@ -181,7 +181,7 @@ export interface ExportContext {
|
|||||||
options: ExportOptions;
|
options: ExportOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You can attach your own custom data using this propery - it will then be passed to each event handler, allowing you to keep state from one event to the next.
|
* You can attach your own custom data using this property - it will then be passed to each event handler, allowing you to keep state from one event to the next.
|
||||||
*/
|
*/
|
||||||
userData?: any;
|
userData?: any;
|
||||||
}
|
}
|
||||||
@ -553,7 +553,7 @@ export interface CodeMirrorControl {
|
|||||||
* registers the given [CompletionSource](https://codemirror.net/docs/ref/#autocomplete.CompletionSource).
|
* registers the given [CompletionSource](https://codemirror.net/docs/ref/#autocomplete.CompletionSource).
|
||||||
*
|
*
|
||||||
* Use this extension rather than the built-in CodeMirror [`autocompletion`](https://codemirror.net/docs/ref/#autocomplete.autocompletion)
|
* Use this extension rather than the built-in CodeMirror [`autocompletion`](https://codemirror.net/docs/ref/#autocomplete.autocompletion)
|
||||||
* if you don't want to use [langaugeData-based autocompletion](https://codemirror.net/docs/ref/#autocomplete.autocompletion^config.override).
|
* if you don't want to use [languageData-based autocompletion](https://codemirror.net/docs/ref/#autocomplete.autocompletion^config.override).
|
||||||
*
|
*
|
||||||
* Using `autocompletion({ override: [ ... ]})` causes errors when done by multiple plugins.
|
* Using `autocompletion({ override: [ ... ]})` causes errors when done by multiple plugins.
|
||||||
*/
|
*/
|
||||||
|
@ -58,7 +58,7 @@ export const defaultState: State = {
|
|||||||
export const utils = {
|
export const utils = {
|
||||||
|
|
||||||
// It is best to use viewsByType instead as this method creates new objects
|
// It is best to use viewsByType instead as this method creates new objects
|
||||||
// which might trigger unecessary renders even when plugin and views haven't changed.
|
// which might trigger unnecessary renders even when plugin and views haven't changed.
|
||||||
viewInfosByType: function(plugins: PluginStates, type: string): ViewInfo[] {
|
viewInfosByType: function(plugins: PluginStates, type: string): ViewInfo[] {
|
||||||
const output: ViewInfo[] = [];
|
const output: ViewInfo[] = [];
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user