Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f9bcc162e | |||
| 27052143ab | |||
| 50d3ddbed5 | |||
| 7ee50113d7 | |||
| 07bd5129ca | |||
| ec7021b436 | |||
| c75439a4b5 | |||
| d21cb78baa | |||
| c371873b7e | |||
| 6220b02ef0 | |||
| 4e15bc0bb1 | |||
| 2f720df9d2 | |||
| d57a303251 | |||
| 13b9f5231c | |||
| 71ed24344c | |||
| 0c8a2a23a7 | |||
| 5738f2a5b3 | |||
| d345c4850f | |||
| eeacd8118f | |||
| f5216e4799 | |||
| 85d13b1d62 | |||
| f5f48ef6c4 | |||
| f1ed114167 | |||
| 70995a7691 | |||
| a82b8cdb37 | |||
| 33511c0c10 | |||
| 04c93d6736 | |||
| 5e11806110 | |||
| 1e1709ca6a | |||
| 37602cfcae | |||
| 0ca0996751 | |||
| 63ebb46049 | |||
| 847766b434 | |||
| 056c40c0d0 | |||
| bff5b015ea | |||
| ee4ce3ffd8 | |||
| a73733d0fc | |||
| 0c5f842626 | |||
| 8b4cf474bd | |||
| 80f269d844 | |||
| 75c9db6432 | |||
| 69e36d2677 | |||
| eb4d86f41d | |||
| b0bf88c487 | |||
| 032ffa8367 | |||
| 7400c91a4f |
@@ -13,6 +13,8 @@ echo "Copying required linux-x64 binaries"
|
||||
|
||||
cp -r bin/better-sqlite3/linux-desktop-better_sqlite3.node $SRC_DIR/node_modules/better-sqlite3/build/Release/better_sqlite3.node
|
||||
|
||||
echo "Packaging linux x64 electron build"
|
||||
|
||||
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
|
||||
|
||||
BUILD_DIR=./dist/trilium-linux-x64
|
||||
|
||||
@@ -13,6 +13,8 @@ cp -r bin/better-sqlite3/mac-better_sqlite3.node $SRC_DIR/node_modules/better-sq
|
||||
|
||||
rm -r $SRC_DIR/src/public/app-dist/*.mobile.*
|
||||
|
||||
echo "Packaging mac x64 electron build"
|
||||
|
||||
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=darwin --arch=x64 --overwrite --icon=images/app-icons/mac/icon.icns
|
||||
|
||||
BUILD_DIR=./dist/trilium-mac-x64
|
||||
|
||||
@@ -13,6 +13,8 @@ cp -r bin/better-sqlite3/win-better_sqlite3.node $SRC_DIR/node_modules/better-sq
|
||||
|
||||
rm -r $SRC_DIR/src/public/app-dist/*.mobile.*
|
||||
|
||||
echo "Packaging windows x64 electron build"
|
||||
|
||||
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=win32 --arch=x64 --overwrite --icon=images/app-icons/win/icon.ico
|
||||
|
||||
BUILD_DIR=./dist/trilium-windows-x64
|
||||
|
||||
@@ -31,6 +31,7 @@ cp webpack-* $DIR/
|
||||
|
||||
# cleanup of useless files in dependencies
|
||||
rm -r $DIR/node_modules/image-q/demo
|
||||
rm -r $DIR/node_modules/better-sqlite3/Release
|
||||
rm -r $DIR/node_modules/better-sqlite3/deps/sqlite3.tar.gz
|
||||
rm -r $DIR/node_modules/@jimp/plugin-print/fonts
|
||||
rm -r $DIR/node_modules/jimp/browser
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
UPDATE attributes SET name = 'archived' WHERE name = 'hideInAutocomplete';
|
||||
@@ -0,0 +1,18 @@
|
||||
const repository = require('../../src/services/repository');
|
||||
|
||||
module.exports = () => {
|
||||
for (const note of repository.getEntities("SELECT * FROM notes WHERE type = 'text' AND isProtected = 0")) {
|
||||
try {
|
||||
let content = note.getContent();
|
||||
|
||||
content = content
|
||||
.replace(/<h1/ig, "<h2")
|
||||
.replace(/<\/h1/ig, "</h2");
|
||||
|
||||
note.setContent(content);
|
||||
}
|
||||
catch (e) {
|
||||
console.log(`Changing note content for note ${note.noteId} failed with: ${e.message} ${e.stack}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
/*! jQuery Fancytree Plugin - 2.36.0 - 2020-07-15T20:15:15Z
|
||||
/*! jQuery Fancytree Plugin - 2.37.0 - 2020-09-11T18:58:08Z
|
||||
* https://github.com/mar10/fancytree
|
||||
* Copyright (c) 2020 Martin Wendt; Licensed MIT
|
||||
*/
|
||||
@@ -1365,8 +1365,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
/** Core Fancytree module.
|
||||
@@ -5763,6 +5763,12 @@ var uniqueId = $.fn.extend( {
|
||||
dataType: source.dataType,
|
||||
}
|
||||
);
|
||||
if (res.error) {
|
||||
tree.warn(
|
||||
"postProcess returned error:",
|
||||
res
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
res = {
|
||||
error: e,
|
||||
@@ -6742,6 +6748,13 @@ var uniqueId = $.fn.extend( {
|
||||
|
||||
// node.debug("nodeSetExpanded(" + flag + ")");
|
||||
|
||||
if ($(node.li).hasClass(opts._classNames.animating)) {
|
||||
node.warn(
|
||||
"setExpanded(" + flag + ") while animating: ignored."
|
||||
);
|
||||
return _getRejectedPromise(node, ["recursion"]);
|
||||
}
|
||||
|
||||
if ((node.expanded && flag) || (!node.expanded && !flag)) {
|
||||
// Nothing to do
|
||||
// node.debug("nodeSetExpanded(" + flag + "): nothing to do");
|
||||
@@ -8057,7 +8070,7 @@ var uniqueId = $.fn.extend( {
|
||||
{
|
||||
/** Version number `"MAJOR.MINOR.PATCH"`
|
||||
* @type {string} */
|
||||
version: "2.36.0", // Set to semver by 'grunt release'
|
||||
version: "2.37.0", // Set to semver by 'grunt release'
|
||||
/** @type {string}
|
||||
* @description `"production" for release builds` */
|
||||
buildType: "production", // Set to 'production' by 'grunt build'
|
||||
@@ -8692,8 +8705,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
// To keep the global namespace clean, we wrap everything in a closure.
|
||||
@@ -8812,7 +8825,7 @@ var uniqueId = $.fn.extend( {
|
||||
// Every extension must be registered by a unique name.
|
||||
name: "childcounter",
|
||||
// Version information should be compliant with [semver](http://semver.org)
|
||||
version: "2.36.0",
|
||||
version: "2.37.0",
|
||||
|
||||
// Extension specific options and their defaults.
|
||||
// This options will be available as `tree.options.childcounter.hideExpanded`
|
||||
@@ -8923,8 +8936,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -9282,7 +9295,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "clones",
|
||||
version: "2.36.0",
|
||||
version: "2.37.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
highlightActiveClones: true, // set 'fancytree-active-clone' on active clones and all peers
|
||||
@@ -9444,8 +9457,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -10019,9 +10032,10 @@ var uniqueId = $.fn.extend( {
|
||||
if (dndOpts.multiSource === false) {
|
||||
SOURCE_NODE_LIST = [node];
|
||||
} else if (dndOpts.multiSource === true) {
|
||||
SOURCE_NODE_LIST = tree.getSelectedNodes();
|
||||
if (!node.isSelected()) {
|
||||
SOURCE_NODE_LIST.unshift(node);
|
||||
if (node.isSelected()) {
|
||||
SOURCE_NODE_LIST = tree.getSelectedNodes();
|
||||
} else {
|
||||
SOURCE_NODE_LIST = [node];
|
||||
}
|
||||
} else {
|
||||
SOURCE_NODE_LIST = dndOpts.multiSource(node, data);
|
||||
@@ -10462,13 +10476,14 @@ var uniqueId = $.fn.extend( {
|
||||
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "dnd5",
|
||||
version: "2.36.0",
|
||||
version: "2.37.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
autoExpandMS: 1500, // Expand nodes after n milliseconds of hovering
|
||||
dropMarkerInsertOffsetX: -16, // Additional offset for drop-marker with hitMode = "before"/"after"
|
||||
dropMarkerOffsetX: -24, // Absolute position offset for .fancytree-drop-marker relatively to ..fancytree-title (icon/img near a node accepting drop)
|
||||
dropMarkerParent: document.body, // Root Container used for drop marker (could be a shadow root)
|
||||
// #1021 `document.body` is not available yet
|
||||
dropMarkerParent: "body", // Root Container used for drop marker (could be a shadow root)
|
||||
multiSource: false, // true: Drag multiple (i.e. selected) nodes. Also a callback() is allowed
|
||||
effectAllowed: "all", // Restrict the possible cursor shapes and modifier operations (can also be set in the dragStart event)
|
||||
// dropEffect: "auto", // 'copy'|'link'|'move'|'auto'(calculate from `effectAllowed`+modifier keys) or callback(node, data) that returns such string.
|
||||
@@ -10597,8 +10612,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -10805,7 +10820,7 @@ var uniqueId = $.fn.extend( {
|
||||
}
|
||||
|
||||
// Set keyboard focus, even if setFocus() claims 'nothing to do'
|
||||
$(tree.$container).focus({ preventScroll: true });
|
||||
tree.$container.get(0).focus({ preventScroll: true });
|
||||
eventData.input = null;
|
||||
instOpts.close.call(node, { type: "close" }, eventData);
|
||||
return true;
|
||||
@@ -10890,7 +10905,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "edit",
|
||||
version: "2.36.0",
|
||||
version: "2.37.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
adjustWidthOfs: 4, // null: don't adjust input size to content
|
||||
@@ -11001,8 +11016,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -11340,7 +11355,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "filter",
|
||||
version: "2.36.0",
|
||||
version: "2.37.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
autoApply: true, // Re-apply last filter if lazy data is loaded
|
||||
@@ -11460,8 +11475,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -11617,13 +11632,32 @@ var uniqueId = $.fn.extend( {
|
||||
},
|
||||
};
|
||||
|
||||
function setIcon(span, baseClass, opts, type) {
|
||||
function setIcon(node, span, baseClass, opts, type) {
|
||||
var map = opts.map,
|
||||
icon = map[type],
|
||||
$span = $(span),
|
||||
$counter = $span.find(".fancytree-childcounter"),
|
||||
setClass = baseClass + " " + (map._addClass || "");
|
||||
|
||||
// #871 Allow a callback
|
||||
if ($.isFunction(icon)) {
|
||||
icon = icon.call(this, node, span, type);
|
||||
}
|
||||
// node.debug( "setIcon(" + baseClass + ", " + type + "): " + "oldIcon" + " -> " + icon );
|
||||
// #871: propsed this, but I am not sure how robust this is, e.g.
|
||||
// the prefix (fas, far) class changes are not considered?
|
||||
// if (span.tagName === "svg" && opts.preset === "awesome5") {
|
||||
// // fa5 script converts <i> to <svg> so call a specific handler.
|
||||
// var oldIcon = "fa-" + $span.data("icon");
|
||||
// // node.debug( "setIcon(" + baseClass + ", " + type + "): " + oldIcon + " -> " + icon );
|
||||
// if (typeof oldIcon === "string") {
|
||||
// $span.removeClass(oldIcon);
|
||||
// }
|
||||
// if (typeof icon === "string") {
|
||||
// $span.addClass(icon);
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
if (typeof icon === "string") {
|
||||
// #883: remove inner html that may be added by prev. mode
|
||||
span.innerHTML = "";
|
||||
@@ -11644,7 +11678,7 @@ var uniqueId = $.fn.extend( {
|
||||
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "glyph",
|
||||
version: "2.36.0",
|
||||
version: "2.37.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
preset: null, // 'awesome3', 'awesome4', 'bootstrap3', 'material'
|
||||
@@ -11681,7 +11715,7 @@ var uniqueId = $.fn.extend( {
|
||||
if (node.isRootNode()) {
|
||||
return res;
|
||||
}
|
||||
span = $span.children("span.fancytree-expander").get(0);
|
||||
span = $span.children(".fancytree-expander").get(0);
|
||||
if (span) {
|
||||
// if( node.isLoading() ){
|
||||
// icon = "loading";
|
||||
@@ -11695,15 +11729,15 @@ var uniqueId = $.fn.extend( {
|
||||
icon = "noExpander";
|
||||
}
|
||||
// span.className = "fancytree-expander " + map[icon];
|
||||
setIcon(span, "fancytree-expander", opts, icon);
|
||||
setIcon(node, span, "fancytree-expander", opts, icon);
|
||||
}
|
||||
|
||||
if (node.tr) {
|
||||
span = $("td", node.tr)
|
||||
.find("span.fancytree-checkbox")
|
||||
.find(".fancytree-checkbox")
|
||||
.get(0);
|
||||
} else {
|
||||
span = $span.children("span.fancytree-checkbox").get(0);
|
||||
span = $span.children(".fancytree-checkbox").get(0);
|
||||
}
|
||||
if (span) {
|
||||
checkbox = FT.evalOption("checkbox", node, node, opts, false);
|
||||
@@ -11713,6 +11747,7 @@ var uniqueId = $.fn.extend( {
|
||||
) {
|
||||
icon = node.selected ? "radioSelected" : "radio";
|
||||
setIcon(
|
||||
node,
|
||||
span,
|
||||
"fancytree-checkbox fancytree-radio",
|
||||
opts,
|
||||
@@ -11726,13 +11761,13 @@ var uniqueId = $.fn.extend( {
|
||||
? "checkboxUnknown"
|
||||
: "checkbox";
|
||||
// span.className = "fancytree-checkbox " + map[icon];
|
||||
setIcon(span, "fancytree-checkbox", opts, icon);
|
||||
setIcon(node, span, "fancytree-checkbox", opts, icon);
|
||||
}
|
||||
}
|
||||
|
||||
// Standard icon (note that this does not match .fancytree-custom-icon,
|
||||
// that might be set by opts.icon callbacks)
|
||||
span = $span.children("span.fancytree-icon").get(0);
|
||||
span = $span.children(".fancytree-icon").get(0);
|
||||
if (span) {
|
||||
if (node.statusNodeType) {
|
||||
icon = node.statusNodeType; // loading, error
|
||||
@@ -11744,7 +11779,7 @@ var uniqueId = $.fn.extend( {
|
||||
} else {
|
||||
icon = node.expanded ? "docOpen" : "doc";
|
||||
}
|
||||
setIcon(span, "fancytree-icon", opts, icon);
|
||||
setIcon(node, span, "fancytree-icon", opts, icon);
|
||||
}
|
||||
return res;
|
||||
},
|
||||
@@ -11762,9 +11797,9 @@ var uniqueId = $.fn.extend( {
|
||||
status === "nodata"
|
||||
) {
|
||||
if (node.parent) {
|
||||
span = $("span.fancytree-expander", node.span).get(0);
|
||||
span = $(".fancytree-expander", node.span).get(0);
|
||||
if (span) {
|
||||
setIcon(span, "fancytree-expander", opts, status);
|
||||
setIcon(node, span, "fancytree-expander", opts, status);
|
||||
}
|
||||
} else {
|
||||
//
|
||||
@@ -11772,10 +11807,10 @@ var uniqueId = $.fn.extend( {
|
||||
".fancytree-statusnode-" + status,
|
||||
node[this.nodeContainerAttrName]
|
||||
)
|
||||
.find("span.fancytree-icon")
|
||||
.find(".fancytree-icon")
|
||||
.get(0);
|
||||
if (span) {
|
||||
setIcon(span, "fancytree-icon", opts, status);
|
||||
setIcon(node, span, "fancytree-icon", opts, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11798,8 +11833,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -11916,7 +11951,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "gridnav",
|
||||
version: "2.36.0",
|
||||
version: "2.37.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
autofocusInput: false, // Focus first embedded input if node gets activated
|
||||
@@ -12023,8 +12058,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -12053,7 +12088,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "multi",
|
||||
version: "2.36.0",
|
||||
version: "2.37.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
allowNoSelect: false, //
|
||||
@@ -12155,8 +12190,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -12179,38 +12214,49 @@ var uniqueId = $.fn.extend( {
|
||||
* Private functions and variables
|
||||
*/
|
||||
var cookieStore = null,
|
||||
localStorageStore = window.localStorage
|
||||
? {
|
||||
get: function(key) {
|
||||
return window.localStorage.getItem(key);
|
||||
},
|
||||
set: function(key, value) {
|
||||
window.localStorage.setItem(key, value);
|
||||
},
|
||||
remove: function(key) {
|
||||
window.localStorage.removeItem(key);
|
||||
},
|
||||
}
|
||||
: null,
|
||||
sessionStorageStore = window.sessionStorage
|
||||
? {
|
||||
get: function(key) {
|
||||
return window.sessionStorage.getItem(key);
|
||||
},
|
||||
set: function(key, value) {
|
||||
window.sessionStorage.setItem(key, value);
|
||||
},
|
||||
remove: function(key) {
|
||||
window.sessionStorage.removeItem(key);
|
||||
},
|
||||
}
|
||||
: null,
|
||||
localStorageStore = null,
|
||||
sessionStorageStore = null,
|
||||
_assert = $.ui.fancytree.assert,
|
||||
ACTIVE = "active",
|
||||
EXPANDED = "expanded",
|
||||
FOCUS = "focus",
|
||||
SELECTED = "selected";
|
||||
|
||||
// Accessing window.xxxStorage may raise security exceptions (see #1022)
|
||||
try {
|
||||
_assert(window.localStorage && window.localStorage.getItem);
|
||||
localStorageStore = {
|
||||
get: function(key) {
|
||||
return window.localStorage.getItem(key);
|
||||
},
|
||||
set: function(key, value) {
|
||||
window.localStorage.setItem(key, value);
|
||||
},
|
||||
remove: function(key) {
|
||||
window.localStorage.removeItem(key);
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
$.ui.fancytree.warn("Could not access window.localStorage", e);
|
||||
}
|
||||
|
||||
try {
|
||||
_assert(window.sessionStorage && window.sessionStorage.getItem);
|
||||
sessionStorageStore = {
|
||||
get: function(key) {
|
||||
return window.sessionStorage.getItem(key);
|
||||
},
|
||||
set: function(key, value) {
|
||||
window.sessionStorage.setItem(key, value);
|
||||
},
|
||||
remove: function(key) {
|
||||
window.sessionStorage.removeItem(key);
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
$.ui.fancytree.warn("Could not access window.sessionStorage", e);
|
||||
}
|
||||
|
||||
if (typeof Cookies === "function") {
|
||||
// Assume https://github.com/js-cookie/js-cookie
|
||||
cookieStore = {
|
||||
@@ -12356,7 +12402,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "persist",
|
||||
version: "2.36.0",
|
||||
version: "2.37.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
cookieDelimiter: "~",
|
||||
@@ -12649,8 +12695,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -12733,7 +12779,7 @@ var uniqueId = $.fn.extend( {
|
||||
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "table",
|
||||
version: "2.36.0",
|
||||
version: "2.37.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
checkboxColumnIdx: null, // render the checkboxes into the this column index (default: nodeColumnIdx)
|
||||
@@ -13199,8 +13245,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -13223,7 +13269,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "themeroller",
|
||||
version: "2.36.0",
|
||||
version: "2.37.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
activeClass: "ui-state-active", // Class added to active node
|
||||
@@ -13319,8 +13365,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -13450,7 +13496,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "wide",
|
||||
version: "2.36.0",
|
||||
version: "2.37.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
iconWidth: null, // Adjust this if @fancy-icon-width != "16px"
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.36.0
|
||||
* @date 2020-07-15T20:15:15Z
|
||||
* @version 2.37.0
|
||||
* @date 2020-09-11T18:58:08Z
|
||||
******************************************************************************/
|
||||
/*------------------------------------------------------------------------------
|
||||
* Helpers
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Generated
+352
-198
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "trilium",
|
||||
"version": "0.43.4",
|
||||
"version": "0.44.2-beta",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -35,9 +35,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "6.12.3",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz",
|
||||
"integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==",
|
||||
"version": "6.12.5",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz",
|
||||
"integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
@@ -649,9 +649,9 @@
|
||||
"integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ=="
|
||||
},
|
||||
"@types/eslint": {
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.1.tgz",
|
||||
"integrity": "sha512-WjKivjZyeL65Qt8HLLGwyhC3NkhoPVgCvxPcCMb02k8fCSJH1vvDRefXmSHA4U9TcjOj024yCOxFgCPKC0gMXQ==",
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.2.tgz",
|
||||
"integrity": "sha512-psWuwNXuKR2e6vMU5d2qH0Kqzrb2Zxwk+uBCF2LsyEph+Nex3lFIPMJXwxfGesdtJM2qtjKoCYsyh76K3x9wLg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/estree": "*",
|
||||
@@ -695,9 +695,9 @@
|
||||
}
|
||||
},
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz",
|
||||
"integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==",
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
|
||||
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/minimatch": {
|
||||
@@ -1139,9 +1139,9 @@
|
||||
}
|
||||
},
|
||||
"aggregate-error": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
|
||||
"integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==",
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
|
||||
"integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"clean-stack": "^2.0.0",
|
||||
@@ -1160,9 +1160,9 @@
|
||||
}
|
||||
},
|
||||
"ajv-keywords": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz",
|
||||
"integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==",
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
|
||||
"integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-align": {
|
||||
@@ -1250,27 +1250,27 @@
|
||||
"integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="
|
||||
},
|
||||
"app-builder-bin": {
|
||||
"version": "3.5.9",
|
||||
"resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.9.tgz",
|
||||
"integrity": "sha512-NSjtqZ3x2kYiDp3Qezsgukx/AUzKPr3Xgf9by4cYt05ILWGAptepeeu0Uv+7MO+41o6ujhLixTou8979JGg2Kg==",
|
||||
"version": "3.5.10",
|
||||
"resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.10.tgz",
|
||||
"integrity": "sha512-Jd+GW68lR0NeetgZDo47PdWBEPdnD+p0jEa7XaxjRC8u6Oo/wgJsfKUkORRgr2NpkD19IFKN50P6JYy04XHFLQ==",
|
||||
"dev": true
|
||||
},
|
||||
"app-builder-lib": {
|
||||
"version": "22.8.0",
|
||||
"resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.8.0.tgz",
|
||||
"integrity": "sha512-RGaIRjCUrqkmh6QOGsyekQPEOaVynHfmeh8JZuyUymFYUOFdzBbPamkA2nhBVBTkkgfjRHsxK7LhedFKPzvWEQ==",
|
||||
"version": "22.8.1",
|
||||
"resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.8.1.tgz",
|
||||
"integrity": "sha512-D/ac1+vuGIAAwEeTtXl8b+qWl7Gz/IQatFyzYl2ocag/7N8LqUjKzZFJJISQPWt6PFDPDH0oCj8/GMh63aV0yw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"7zip-bin": "~5.0.3",
|
||||
"@develar/schema-utils": "~2.6.5",
|
||||
"async-exit-hook": "^2.0.1",
|
||||
"bluebird-lst": "^1.0.9",
|
||||
"builder-util": "22.8.0",
|
||||
"builder-util": "22.8.1",
|
||||
"builder-util-runtime": "8.7.2",
|
||||
"chromium-pickle-js": "^0.2.0",
|
||||
"debug": "^4.1.1",
|
||||
"debug": "^4.2.0",
|
||||
"ejs": "^3.1.3",
|
||||
"electron-publish": "22.8.0",
|
||||
"electron-publish": "22.8.1",
|
||||
"fs-extra": "^9.0.1",
|
||||
"hosted-git-info": "^3.0.5",
|
||||
"is-ci": "^2.0.0",
|
||||
@@ -1285,6 +1285,15 @@
|
||||
"temp-file": "^3.3.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
|
||||
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"hosted-git-info": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.5.tgz",
|
||||
@@ -1294,19 +1303,10 @@
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@@ -1595,9 +1595,9 @@
|
||||
}
|
||||
},
|
||||
"better-sqlite3": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-7.1.0.tgz",
|
||||
"integrity": "sha512-FV/snQ8F/kyqhdxsevzbojVtMowDWOfe1A5N3lYu1KJwoho2t7JgITmdlSc7DkOh3Zq65I+ZyeNWXQrkLEDFTg==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-7.1.1.tgz",
|
||||
"integrity": "sha512-AkvGGyhAVZhRBOul2WT+5CB2EuveM3ZkebEKe1wxMqDZUy1XB/1RBgM66t0ybHC4DIni8+pr7NaLqEX87NUTwg==",
|
||||
"requires": {
|
||||
"bindings": "^1.5.0",
|
||||
"prebuild-install": "^5.3.3",
|
||||
@@ -1628,6 +1628,33 @@
|
||||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"bl": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz",
|
||||
"integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==",
|
||||
"requires": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"bluebird": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.0.tgz",
|
||||
@@ -1856,19 +1883,19 @@
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||
},
|
||||
"builder-util": {
|
||||
"version": "22.8.0",
|
||||
"resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.8.0.tgz",
|
||||
"integrity": "sha512-H80P1JzVy3TGpi63x81epQDK24XalL034+jAZlrPb5IhLtYmnNNdxCCAVJvg3VjSISd73Y71O+uhqCxWpqbPHw==",
|
||||
"version": "22.8.1",
|
||||
"resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.8.1.tgz",
|
||||
"integrity": "sha512-LZG+E1xszMdut5hL5h7RkJQ7yOsQqdhJYgn1wvOP7MmF3MoUPRNDiRodLpYiWlaqZmgYhcfaipR/Mb8F/RqK8w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"7zip-bin": "~5.0.3",
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/fs-extra": "^9.0.1",
|
||||
"app-builder-bin": "3.5.9",
|
||||
"app-builder-bin": "3.5.10",
|
||||
"bluebird-lst": "^1.0.9",
|
||||
"builder-util-runtime": "8.7.2",
|
||||
"chalk": "^4.1.0",
|
||||
"debug": "^4.1.1",
|
||||
"debug": "^4.2.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
"is-ci": "^2.0.0",
|
||||
"js-yaml": "^3.14.0",
|
||||
@@ -1911,6 +1938,21 @@
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
|
||||
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -2057,9 +2099,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"get-stream": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz",
|
||||
"integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
|
||||
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pump": "^3.0.0"
|
||||
@@ -2138,9 +2180,9 @@
|
||||
}
|
||||
},
|
||||
"chownr": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz",
|
||||
"integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw=="
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
|
||||
},
|
||||
"chrome-trace-event": {
|
||||
"version": "1.0.2",
|
||||
@@ -2192,9 +2234,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"cli-boxes": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz",
|
||||
"integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==",
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz",
|
||||
"integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==",
|
||||
"dev": true
|
||||
},
|
||||
"cli-cursor": {
|
||||
@@ -2467,14 +2509,26 @@
|
||||
"dev": true
|
||||
},
|
||||
"commonmark": {
|
||||
"version": "0.29.1",
|
||||
"resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.29.1.tgz",
|
||||
"integrity": "sha512-DafPdNYFXoEhsSiR4O+dJ45UJBfDL4cBTks4B+agKiaWt7qjG0bIhg5xuCE0RqU71ikJcBIf4/sRHh9vYQVF8Q==",
|
||||
"version": "0.29.2",
|
||||
"resolved": "https://registry.npmjs.org/commonmark/-/commonmark-0.29.2.tgz",
|
||||
"integrity": "sha512-spe43MvEIaPpHss1T7z4yQaFQfLGmMu+yvCwv6xqhELIwkG/ZGgDpxOPzKxnuYzYT2c+aziCCc8m2rBVLA7jUA==",
|
||||
"requires": {
|
||||
"entities": "~1.1.1",
|
||||
"entities": "~2.0",
|
||||
"mdurl": "~1.0.1",
|
||||
"minimist": "~1.2.0",
|
||||
"minimist": ">=1.2.2",
|
||||
"string.prototype.repeat": "^0.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"entities": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
|
||||
"integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ=="
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"compare-version": {
|
||||
@@ -2801,9 +2855,9 @@
|
||||
}
|
||||
},
|
||||
"dayjs": {
|
||||
"version": "1.8.35",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.35.tgz",
|
||||
"integrity": "sha512-isAbIEenO4ilm6f8cpqvgjZCsuerDAz2Kb7ri201AiNn58aqXuaLJEnCtfIMdCvERZHNGRY5lDMTr/jdAnKSWQ=="
|
||||
"version": "1.8.36",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz",
|
||||
"integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
@@ -2986,13 +3040,13 @@
|
||||
}
|
||||
},
|
||||
"dmg-builder": {
|
||||
"version": "22.8.0",
|
||||
"resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.8.0.tgz",
|
||||
"integrity": "sha512-orePWjcrl97SYLA8F/6UUtbXJSoZCYu5KOP1lVqD4LOomr8bjGDyEVYZmZYcg5WqKmXucdmO6OpqgzH/aRMMuA==",
|
||||
"version": "22.8.1",
|
||||
"resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.8.1.tgz",
|
||||
"integrity": "sha512-WeGom1moM00gBII6swljl4DQGrlJuEivoUhOmh8U9p1ALgeJL+EiTHbZFERlj8Ejy62xUUjURV+liOxUKmJFWg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"app-builder-lib": "22.8.0",
|
||||
"builder-util": "22.8.0",
|
||||
"app-builder-lib": "22.8.1",
|
||||
"builder-util": "22.8.1",
|
||||
"fs-extra": "^9.0.1",
|
||||
"iconv-lite": "^0.6.2",
|
||||
"js-yaml": "^3.14.0",
|
||||
@@ -3055,9 +3109,9 @@
|
||||
}
|
||||
},
|
||||
"dot-prop": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz",
|
||||
"integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==",
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
|
||||
"integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-obj": "^2.0.0"
|
||||
@@ -3104,9 +3158,9 @@
|
||||
}
|
||||
},
|
||||
"electron": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-9.3.0.tgz",
|
||||
"integrity": "sha512-7zPLEZ+kOjVJqfawMQ0vVuZZRqvZIeiID3tbjjbVybbxXIlFMpZ2jogoh7PV3rLrtm+dKRfu7Qc4E7ob1d0FqQ==",
|
||||
"version": "9.3.1",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-9.3.1.tgz",
|
||||
"integrity": "sha512-DScrhqBT4a54KfdF0EoipALpHmdQTn3m7SSCtbpTcEcG+UDUiXad2cOfW6DHeVH7N+CVDKDG12q2PhVJjXkFAA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@electron/get": "^1.0.1",
|
||||
@@ -3115,25 +3169,25 @@
|
||||
}
|
||||
},
|
||||
"electron-builder": {
|
||||
"version": "22.8.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.8.0.tgz",
|
||||
"integrity": "sha512-dUv4F3srJouqxhWivtKqSoQP4Df6vYgjooGdzms+iYMTFi9f0b4LlEbr7kgsPvte8zAglee7VOGOODkCRJDkUQ==",
|
||||
"version": "22.8.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.8.1.tgz",
|
||||
"integrity": "sha512-Hs7KTMq1rGSvT0fwGKXrjbLiJkK6sAKDQooUSwklOkktUgWi4ATjlP0fVE3l8SmS7zcLoww2yDZonSDqxEFhaQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/yargs": "^15.0.5",
|
||||
"app-builder-lib": "22.8.0",
|
||||
"app-builder-lib": "22.8.1",
|
||||
"bluebird-lst": "^1.0.9",
|
||||
"builder-util": "22.8.0",
|
||||
"builder-util": "22.8.1",
|
||||
"builder-util-runtime": "8.7.2",
|
||||
"chalk": "^4.1.0",
|
||||
"dmg-builder": "22.8.0",
|
||||
"dmg-builder": "22.8.1",
|
||||
"fs-extra": "^9.0.1",
|
||||
"is-ci": "^2.0.0",
|
||||
"lazy-val": "^1.0.4",
|
||||
"read-config-file": "6.0.0",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"update-notifier": "^4.1.0",
|
||||
"yargs": "^15.3.1"
|
||||
"yargs": "^15.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
@@ -3484,14 +3538,14 @@
|
||||
}
|
||||
},
|
||||
"electron-publish": {
|
||||
"version": "22.8.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.8.0.tgz",
|
||||
"integrity": "sha512-uM0Zdi9hUqqGOrPj478v7toTvV1Kgto1w11rIiI168batiXAJvNLD8VZRfehOrZT0ibUyZlw8FtxoGCrjyHUOw==",
|
||||
"version": "22.8.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.8.1.tgz",
|
||||
"integrity": "sha512-zqI66vl7j1CJZJ60J+1ez1tQNQeuqVspW44JvYDa5kZbM5wSFDAJFMK9RWHOqRF1Ezd4LDeiBa4aeTOwOt9syA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/fs-extra": "^9.0.1",
|
||||
"bluebird-lst": "^1.0.9",
|
||||
"builder-util": "22.8.0",
|
||||
"builder-util": "22.8.1",
|
||||
"builder-util-runtime": "8.7.2",
|
||||
"chalk": "^4.1.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
@@ -3543,9 +3597,9 @@
|
||||
}
|
||||
},
|
||||
"electron-rebuild": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-rebuild/-/electron-rebuild-2.0.1.tgz",
|
||||
"integrity": "sha512-oXCnKKS+FpLxXiiSHtSCFI3zo+4H2y6zUegSQTI031RJXn2fzQV9UJMAfBrnW7Z083chIo3/L4+xFM4R8mreOQ==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/electron-rebuild/-/electron-rebuild-2.0.3.tgz",
|
||||
"integrity": "sha512-I8Oeey9afU+trFLd8/qRRiHC083CCoBnmw3q0qQaRFsg0OzMaeJQn7Nl6EYKPpntuQ/3yOqZQ7b3ObNuETN/Ig==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@malept/cross-spawn-promise": "^1.1.0",
|
||||
@@ -3555,8 +3609,122 @@
|
||||
"fs-extra": "^9.0.1",
|
||||
"node-abi": "^2.19.1",
|
||||
"node-gyp": "^7.1.0",
|
||||
"ora": "^5.0.0",
|
||||
"yargs": "^15.4.1"
|
||||
"ora": "^5.1.0",
|
||||
"yargs": "^16.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
||||
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/color-name": "^1.1.1",
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.1.tgz",
|
||||
"integrity": "sha512-rcvHOWyGyid6I1WjT/3NatKj2kDt9OdSHSXpyLXaMWFbKpGACNW8pRhhdPUq9MWUOdwn8Rz9AVETjF4105rZZQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
||||
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"y18n": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.1.tgz",
|
||||
"integrity": "sha512-/jJ831jEs4vGDbYPQp4yGKDYPSCCEQ45uZWJHE1AoYBzqdZi8+LDWas0z4HrmJXmKdpFsTiowSHXdxyFhpmdMg==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs": {
|
||||
"version": "16.0.3",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.0.3.tgz",
|
||||
"integrity": "sha512-6+nLw8xa9uK1BOEOykaiYAJVh6/CjxWXK/q9b5FpRgNslt8s22F2xMBqVIKgCRjNgGvGPBy8Vog7WN7yh4amtA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cliui": "^7.0.0",
|
||||
"escalade": "^3.0.2",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.0",
|
||||
"y18n": "^5.0.1",
|
||||
"yargs-parser": "^20.0.0"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "20.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.0.0.tgz",
|
||||
"integrity": "sha512-8eblPHTL7ZWRkyjIZJjnGf+TijiKJSwA24svzLRVvtgoi/RZiKa9fFQTrlx0OKLnyHSdt/enrdadji6WFfESVA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"electron-window-state": {
|
||||
@@ -3595,13 +3763,21 @@
|
||||
}
|
||||
},
|
||||
"enhanced-resolve": {
|
||||
"version": "5.0.0-beta.10",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.0.0-beta.10.tgz",
|
||||
"integrity": "sha512-vEyxvHv3f8xl7i7QmTQ6BqKY32acSPQ4dTZo8WRMtcqTDYH9YyXnDxqXsQqBLvdRHUiwl9nVivESiM1RcrxbKQ==",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.0.0.tgz",
|
||||
"integrity": "sha512-6F037vvK16tgLlRgUx6ZEZISMysNvnnk09SILFrx3bNa1UsSLpIXFzWOmtiDxf1ISPAG6/wHBI61PEkeuTLVNA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"tapable": "^2.0.0-beta.10"
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"graceful-fs": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
||||
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"enquirer": {
|
||||
@@ -3640,6 +3816,12 @@
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"escalade": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz",
|
||||
"integrity": "sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ==",
|
||||
"dev": true
|
||||
},
|
||||
"escape-goat": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
|
||||
@@ -3668,12 +3850,12 @@
|
||||
}
|
||||
},
|
||||
"eslint-scope": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz",
|
||||
"integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==",
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
|
||||
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esrecurse": "^4.1.0",
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^4.1.1"
|
||||
}
|
||||
},
|
||||
@@ -3689,12 +3871,20 @@
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
},
|
||||
"esrecurse": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
|
||||
"integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
|
||||
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"estraverse": "^4.1.0"
|
||||
"estraverse": "^5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"estraverse": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
|
||||
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"estraverse": {
|
||||
@@ -4017,9 +4207,9 @@
|
||||
}
|
||||
},
|
||||
"file-type": {
|
||||
"version": "15.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-15.0.0.tgz",
|
||||
"integrity": "sha512-l0JCuF5F7NIybCfa9G2H0lKhhGaf0z+HJyLOmB2feknY7/HBVNyD4PLesGKLGqznwyVXGNnfpIOr+Fvca6bOEg==",
|
||||
"version": "15.0.1",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-15.0.1.tgz",
|
||||
"integrity": "sha512-0LieQlSA3bWUdErNrxzxfI4rhsvNAVPBO06R8pTc1hp9SE6nhqlVyvhcaXoMmtXkBTPnQenbMPLW9X76hH76oQ==",
|
||||
"requires": {
|
||||
"readable-web-to-node-stream": "^2.0.0",
|
||||
"strtok3": "^6.0.3",
|
||||
@@ -4604,9 +4794,9 @@
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
|
||||
},
|
||||
"helmet": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/helmet/-/helmet-4.1.0.tgz",
|
||||
"integrity": "sha512-KWy75fYN8hOG2Rhl8e5B3WhOzb0by1boQum85TiddIE9iu6gV+TXbUjVC17wfej0o/ZUpqB9kxM0NFCZRMzf+Q=="
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/helmet/-/helmet-4.1.1.tgz",
|
||||
"integrity": "sha512-Avg4XxSBrehD94mkRwEljnO+6RZx7AGfk8Wa6K1nxaU+hbXlFOhlOIMgPfFqOYQB/dBCsTpootTGuiOG+CHiQA=="
|
||||
},
|
||||
"hosted-git-info": {
|
||||
"version": "2.8.5",
|
||||
@@ -6341,9 +6531,9 @@
|
||||
}
|
||||
},
|
||||
"ora": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ora/-/ora-5.0.0.tgz",
|
||||
"integrity": "sha512-s26qdWqke2kjN/wC4dy+IQPBIMWBJlSU/0JZhk30ZDBLelW25rv66yutUWARMigpGPzcXHb+Nac5pNhN/WsARw==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ora/-/ora-5.1.0.tgz",
|
||||
"integrity": "sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^4.1.0",
|
||||
@@ -6748,9 +6938,9 @@
|
||||
}
|
||||
},
|
||||
"prebuild-install": {
|
||||
"version": "5.3.4",
|
||||
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.4.tgz",
|
||||
"integrity": "sha512-AkKN+pf4fSEihjapLEEj8n85YIw/tN6BQqkhzbDc0RvEZGdkpJBGMUYx66AAMcPG2KzmPQS7Cm16an4HVBRRMA==",
|
||||
"version": "5.3.5",
|
||||
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.5.tgz",
|
||||
"integrity": "sha512-YmMO7dph9CYKi5IR/BzjOJlRzpxGGVo1EsLSUZ0mt/Mq0HWZIHOKHHcHdT69yG54C9m6i45GpItwRHpk0Py7Uw==",
|
||||
"requires": {
|
||||
"detect-libc": "^1.0.3",
|
||||
"expand-template": "^2.0.3",
|
||||
@@ -6773,14 +6963,6 @@
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -7391,20 +7573,20 @@
|
||||
}
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
|
||||
"integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
|
||||
"integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/json-schema": "^7.0.4",
|
||||
"ajv": "^6.12.2",
|
||||
"ajv-keywords": "^3.4.1"
|
||||
"@types/json-schema": "^7.0.5",
|
||||
"ajv": "^6.12.4",
|
||||
"ajv-keywords": "^3.5.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": {
|
||||
"version": "6.12.4",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
|
||||
"integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==",
|
||||
"version": "6.12.5",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz",
|
||||
"integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
@@ -7512,9 +7694,9 @@
|
||||
}
|
||||
},
|
||||
"serialize-javascript": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
|
||||
"integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
|
||||
"integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"randombytes": "^2.1.0"
|
||||
@@ -7633,9 +7815,9 @@
|
||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
|
||||
},
|
||||
"simple-concat": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
|
||||
"integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY="
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
|
||||
},
|
||||
"simple-get": {
|
||||
"version": "3.1.0",
|
||||
@@ -7993,11 +8175,6 @@
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
|
||||
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
|
||||
},
|
||||
"string-similarity": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-4.0.2.tgz",
|
||||
"integrity": "sha512-eCsPPyoQBgY4TMpVD6DVfO7pLrimUONriaO4Xjp3WPUW0YnNLqdHgRj23xotLlqrL90eJhBeq3zdAJf2mQgfBQ=="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||
@@ -8117,9 +8294,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"tapable": {
|
||||
"version": "2.0.0-beta.11",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.0.0-beta.11.tgz",
|
||||
"integrity": "sha512-cAhRzCvMdyJsxmdrSXG8/SUlJG4WJUxD/csuYAybUFjKVt74Y6pTyZ/I1ZK+enmCkWZN0JWxh14G69temaGSiA==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.0.0.tgz",
|
||||
"integrity": "sha512-bjzn0C0RWoffnNdTzNi7rNDhs1Zlwk2tRXgk8EiHKAOX1Mag3d6T0Y5zNa7l9CJ+EoUne/0UHdwS8tMbkh9zDg==",
|
||||
"dev": true
|
||||
},
|
||||
"tar": {
|
||||
@@ -8196,25 +8373,17 @@
|
||||
}
|
||||
},
|
||||
"tar-stream": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz",
|
||||
"integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==",
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz",
|
||||
"integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==",
|
||||
"requires": {
|
||||
"bl": "^4.0.1",
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"bl": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.0.1.tgz",
|
||||
"integrity": "sha512-FL/TdvchukRCuWVxT0YMO/7+L5TNeNrVFvRU2IY63aUyv9mpt8splf2NEr6qXtPo5fya5a66YohQKvGNmLrWNA==",
|
||||
"requires": {
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
@@ -8257,9 +8426,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"terser": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.2.1.tgz",
|
||||
"integrity": "sha512-/AOtjRtAMNGO0fIF6m8HfcvXTw/2AKpsOzDn36tA5RfhRdeXyb4RvHxJ5Pah7iL6dFkLk+gOnCaNHGwJPl6TrQ==",
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.3.2.tgz",
|
||||
"integrity": "sha512-H67sydwBz5jCUA32ZRL319ULu+Su1cAoZnnc+lXnenGRYWyLE3Scgkt8mNoAsMx0h5kdo758zdoS0LG9rYZXDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "^2.20.0",
|
||||
@@ -8276,19 +8445,19 @@
|
||||
}
|
||||
},
|
||||
"terser-webpack-plugin": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.1.0.tgz",
|
||||
"integrity": "sha512-0ZWDPIP8BtEDZdChbufcXUigOYk6dOX/P/X0hWxqDDcVAQLb8Yy/0FAaemSfax3PAA67+DJR778oz8qVbmy4hA==",
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.2.1.tgz",
|
||||
"integrity": "sha512-D0IZQNl1ZN/JivFNDFzOeU2Bk2LdQQESHJhKTHsodpUmISkaeRwVFk7gzHzX4OuQwanDGelOxIEsBt1SZ+s6nA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cacache": "^15.0.5",
|
||||
"find-cache-dir": "^3.3.1",
|
||||
"jest-worker": "^26.3.0",
|
||||
"p-limit": "^3.0.2",
|
||||
"schema-utils": "^2.6.6",
|
||||
"serialize-javascript": "^4.0.0",
|
||||
"schema-utils": "^2.7.1",
|
||||
"serialize-javascript": "^5.0.1",
|
||||
"source-map": "^0.6.1",
|
||||
"terser": "^5.0.0",
|
||||
"terser": "^5.3.1",
|
||||
"webpack-sources": "^1.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -8716,9 +8885,9 @@
|
||||
}
|
||||
},
|
||||
"update-notifier": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.0.tgz",
|
||||
"integrity": "sha512-w3doE1qtI0/ZmgeoDoARmI5fjDoT93IfKgEGqm26dGUOh8oNpaSTsGNdYRN/SjOuo10jcJGwkEL3mroKzktkew==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.1.tgz",
|
||||
"integrity": "sha512-9y+Kds0+LoLG6yN802wVXoIfxYEwh3FlZwzMwpCZp62S2i1/Jzeqb9Eeeju3NSHccGGasfGlK5/vEHbAifYRDg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"boxen": "^4.2.0",
|
||||
@@ -8878,9 +9047,9 @@
|
||||
}
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "2.0.0-beta.14",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.0.0-beta.14.tgz",
|
||||
"integrity": "sha512-mToSRWik+KvbvQ0c9Oxy2PjhiCUz5CXx6kpKI9MdJ/fiBDxi0HYx4UTGxQoHIEA7aXQKJrfNUhw9OeH2bc4Wvg==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.0.0.tgz",
|
||||
"integrity": "sha512-xSdCxxYZWNk3VK13bZRYhsQpfa8Vg63zXG+3pyU8ouqSLRCv4IGXIp9Kr226q6GBkGRlZrST2wwKtjfKz2m7Cg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
@@ -8902,9 +9071,9 @@
|
||||
"integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.0.0-beta.28",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.0.0-beta.28.tgz",
|
||||
"integrity": "sha512-NVaE2s4YlhP07eFtfw8mmBKlRQYcc+vjLIVyLSaawCvJdt7i53oHDe2K8zTDNCNcP/HWluEg9kghV19LBE2T4A==",
|
||||
"version": "5.0.0-beta.32",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.0.0-beta.32.tgz",
|
||||
"integrity": "sha512-PrEyICK8AGeY/yK6yuHk7iuo5y1lMOuD2tI0rM+pG8ZYR6tjdkmvvu0kJGBeor9AaPjB46YA4BDBigMdBLCFCA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/eslint-scope": "^3.7.0",
|
||||
@@ -8915,8 +9084,7 @@
|
||||
"@webassemblyjs/wasm-parser": "1.9.0",
|
||||
"acorn": "^7.4.0",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"core-js": "^3.6.5",
|
||||
"enhanced-resolve": "5.0.0-beta.10",
|
||||
"enhanced-resolve": "^5.0.0",
|
||||
"eslint-scope": "^5.1.0",
|
||||
"events": "^3.2.0",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
@@ -8927,10 +9095,10 @@
|
||||
"neo-async": "^2.6.2",
|
||||
"pkg-dir": "^4.2.0",
|
||||
"schema-utils": "^2.7.0",
|
||||
"tapable": "^2.0.0-beta.11",
|
||||
"tapable": "^2.0.0",
|
||||
"terser-webpack-plugin": "^4.1.0",
|
||||
"watchpack": "2.0.0-beta.14",
|
||||
"webpack-sources": "2.0.0-beta.9"
|
||||
"watchpack": "^2.0.0",
|
||||
"webpack-sources": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
@@ -8939,12 +9107,6 @@
|
||||
"integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==",
|
||||
"dev": true
|
||||
},
|
||||
"core-js": {
|
||||
"version": "3.6.5",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz",
|
||||
"integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==",
|
||||
"dev": true
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
||||
@@ -9190,9 +9352,9 @@
|
||||
}
|
||||
},
|
||||
"webpack-sources": {
|
||||
"version": "2.0.0-beta.9",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.0.0-beta.9.tgz",
|
||||
"integrity": "sha512-q6O+gKGojLye0Fm05vgthtmx5LPbYpAU4FsdMsX8YBgkOZovDbQmBMhjY/CiWhxD9u/0AWeWdXFNbQz17mkdLw==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.0.0.tgz",
|
||||
"integrity": "sha512-CpCkDjEKa5vYVRDFDRABBkBomz+82lz9bpXViN1LBc8L/WDXvSyELKcBvBnTeDEiRfMJCGAFG9+04406PLSsIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"source-list-map": "^2.0.1",
|
||||
@@ -9582,14 +9744,6 @@
|
||||
"requires": {
|
||||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"yauzl": {
|
||||
|
||||
+10
-11
@@ -2,7 +2,7 @@
|
||||
"name": "trilium",
|
||||
"productName": "Trilium Notes",
|
||||
"description": "Trilium Notes",
|
||||
"version": "0.44.1-beta",
|
||||
"version": "0.44.3-beta",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "electron.js",
|
||||
"bin": {
|
||||
@@ -26,13 +26,13 @@
|
||||
"dependencies": {
|
||||
"async-mutex": "0.2.4",
|
||||
"axios": "0.20.0",
|
||||
"better-sqlite3": "7.1.0",
|
||||
"better-sqlite3": "7.1.1",
|
||||
"body-parser": "1.19.0",
|
||||
"cls-hooked": "4.2.2",
|
||||
"commonmark": "0.29.1",
|
||||
"commonmark": "0.29.2",
|
||||
"cookie-parser": "1.4.5",
|
||||
"csurf": "1.11.0",
|
||||
"dayjs": "1.8.35",
|
||||
"dayjs": "1.8.36",
|
||||
"debug": "4.1.1",
|
||||
"ejs": "3.1.5",
|
||||
"electron-debug": "3.1.0",
|
||||
@@ -41,9 +41,9 @@
|
||||
"electron-window-state": "5.0.3",
|
||||
"express": "4.17.1",
|
||||
"express-session": "1.17.1",
|
||||
"file-type": "15.0.0",
|
||||
"file-type": "15.0.1",
|
||||
"fs-extra": "9.0.1",
|
||||
"helmet": "4.1.0",
|
||||
"helmet": "4.1.1",
|
||||
"html": "1.0.0",
|
||||
"html2plaintext": "2.1.2",
|
||||
"http-proxy-agent": "4.0.1",
|
||||
@@ -66,7 +66,6 @@
|
||||
"semver": "7.3.2",
|
||||
"serve-favicon": "2.5.0",
|
||||
"session-file-store": "1.4.0",
|
||||
"string-similarity": "4.0.2",
|
||||
"striptags": "3.1.1",
|
||||
"turndown": "6.0.0",
|
||||
"turndown-plugin-gfm": "1.0.2",
|
||||
@@ -77,16 +76,16 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "7.0.2",
|
||||
"electron": "9.3.0",
|
||||
"electron-builder": "22.8.0",
|
||||
"electron": "9.3.1",
|
||||
"electron-builder": "22.8.1",
|
||||
"electron-packager": "15.1.0",
|
||||
"electron-rebuild": "2.0.1",
|
||||
"electron-rebuild": "2.0.3",
|
||||
"esm": "3.2.25",
|
||||
"jasmine": "3.6.1",
|
||||
"jsdoc": "3.6.5",
|
||||
"lorem-ipsum": "2.0.3",
|
||||
"rcedit": "2.2.0",
|
||||
"webpack": "5.0.0-beta.28",
|
||||
"webpack": "5.0.0-beta.32",
|
||||
"webpack-cli": "4.0.0-beta.8"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
||||
+23
-23
@@ -1,4 +1,4 @@
|
||||
const ParsingContext = require("../../src/services/search/parsing_context.js");
|
||||
const SearchContext = require("../../src/services/search/search_context.js");
|
||||
const parse = require('../../src/services/search/services/parse.js');
|
||||
|
||||
function tokens(toks, cur = 0) {
|
||||
@@ -24,7 +24,7 @@ describe("Parser", () => {
|
||||
const rootExp = parse({
|
||||
fulltextTokens: tokens(["hello", "hi"]),
|
||||
expressionTokens: [],
|
||||
parsingContext: new ParsingContext({includeNoteContent: false})
|
||||
searchContext: new SearchContext({includeNoteContent: false})
|
||||
});
|
||||
|
||||
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||
@@ -36,7 +36,7 @@ describe("Parser", () => {
|
||||
const rootExp = parse({
|
||||
fulltextTokens: tokens(["hello", "hi"]),
|
||||
expressionTokens: [],
|
||||
parsingContext: new ParsingContext({includeNoteContent: true})
|
||||
searchContext: new SearchContext({includeNoteContent: true})
|
||||
});
|
||||
|
||||
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||
@@ -59,7 +59,7 @@ describe("Parser", () => {
|
||||
const rootExp = parse({
|
||||
fulltextTokens: [],
|
||||
expressionTokens: tokens(["#mylabel", "=", "text"]),
|
||||
parsingContext: new ParsingContext()
|
||||
searchContext: new SearchContext()
|
||||
});
|
||||
|
||||
expect(rootExp.constructor.name).toEqual("LabelComparisonExp");
|
||||
@@ -72,7 +72,7 @@ describe("Parser", () => {
|
||||
let rootExp = parse({
|
||||
fulltextTokens: [],
|
||||
expressionTokens: tokens(["#!mylabel"]),
|
||||
parsingContext: new ParsingContext()
|
||||
searchContext: new SearchContext()
|
||||
});
|
||||
|
||||
expect(rootExp.constructor.name).toEqual("NotExp");
|
||||
@@ -83,7 +83,7 @@ describe("Parser", () => {
|
||||
rootExp = parse({
|
||||
fulltextTokens: [],
|
||||
expressionTokens: tokens(["~!myrelation"]),
|
||||
parsingContext: new ParsingContext()
|
||||
searchContext: new SearchContext()
|
||||
});
|
||||
|
||||
expect(rootExp.constructor.name).toEqual("NotExp");
|
||||
@@ -96,7 +96,7 @@ describe("Parser", () => {
|
||||
const rootExp = parse({
|
||||
fulltextTokens: [],
|
||||
expressionTokens: tokens(["#first", "=", "text", "and", "#second", "=", "text"]),
|
||||
parsingContext: new ParsingContext(true)
|
||||
searchContext: new SearchContext(true)
|
||||
});
|
||||
|
||||
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||
@@ -113,7 +113,7 @@ describe("Parser", () => {
|
||||
const rootExp = parse({
|
||||
fulltextTokens: [],
|
||||
expressionTokens: tokens(["#first", "=", "text", "#second", "=", "text"]),
|
||||
parsingContext: new ParsingContext()
|
||||
searchContext: new SearchContext()
|
||||
});
|
||||
|
||||
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||
@@ -130,7 +130,7 @@ describe("Parser", () => {
|
||||
const rootExp = parse({
|
||||
fulltextTokens: [],
|
||||
expressionTokens: tokens(["#first", "=", "text", "or", "#second", "=", "text"]),
|
||||
parsingContext: new ParsingContext()
|
||||
searchContext: new SearchContext()
|
||||
});
|
||||
|
||||
expect(rootExp.constructor.name).toEqual("OrExp");
|
||||
@@ -147,7 +147,7 @@ describe("Parser", () => {
|
||||
const rootExp = parse({
|
||||
fulltextTokens: tokens(["hello"]),
|
||||
expressionTokens: tokens(["#mylabel", "=", "text"]),
|
||||
parsingContext: new ParsingContext()
|
||||
searchContext: new SearchContext()
|
||||
});
|
||||
|
||||
expect(rootExp.constructor.name).toEqual("AndExp");
|
||||
@@ -165,7 +165,7 @@ describe("Parser", () => {
|
||||
const rootExp = parse({
|
||||
fulltextTokens: [],
|
||||
expressionTokens: tokens(["#first", "=", "text", "or", ["#second", "=", "text", "and", "#third", "=", "text"]]),
|
||||
parsingContext: new ParsingContext()
|
||||
searchContext: new SearchContext()
|
||||
});
|
||||
|
||||
expect(rootExp.constructor.name).toEqual("OrExp");
|
||||
@@ -187,39 +187,39 @@ describe("Parser", () => {
|
||||
|
||||
describe("Invalid expressions", () => {
|
||||
it("incomplete comparison", () => {
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
parse({
|
||||
fulltextTokens: [],
|
||||
expressionTokens: tokens(["#first", "="]),
|
||||
parsingContext
|
||||
searchContext
|
||||
});
|
||||
|
||||
expect(parsingContext.error).toEqual('Misplaced or incomplete expression "="')
|
||||
expect(searchContext.error).toEqual('Misplaced or incomplete expression "="')
|
||||
});
|
||||
|
||||
it("comparison between labels is impossible", () => {
|
||||
let parsingContext = new ParsingContext();
|
||||
parsingContext.originalQuery = "#first = #second";
|
||||
let searchContext = new SearchContext();
|
||||
searchContext.originalQuery = "#first = #second";
|
||||
|
||||
parse({
|
||||
fulltextTokens: [],
|
||||
expressionTokens: tokens(["#first", "=", "#second"]),
|
||||
parsingContext
|
||||
searchContext
|
||||
});
|
||||
|
||||
expect(parsingContext.error).toEqual(`Error near token "#second" in "#first = #second", it's possible to compare with constant only.`);
|
||||
expect(searchContext.error).toEqual(`Error near token "#second" in "#first = #second", it's possible to compare with constant only.`);
|
||||
|
||||
parsingContext = new ParsingContext();
|
||||
parsingContext.originalQuery = "#first = note.relations.second";
|
||||
searchContext = new SearchContext();
|
||||
searchContext.originalQuery = "#first = note.relations.second";
|
||||
|
||||
parse({
|
||||
fulltextTokens: [],
|
||||
expressionTokens: tokens(["#first", "=", "note", ".", "relations", "second"]),
|
||||
parsingContext
|
||||
searchContext
|
||||
});
|
||||
|
||||
expect(parsingContext.error).toEqual(`Error near token "note" in "#first = note.relations.second", it's possible to compare with constant only.`);
|
||||
expect(searchContext.error).toEqual(`Error near token "note" in "#first = note.relations.second", it's possible to compare with constant only.`);
|
||||
|
||||
const rootExp = parse({
|
||||
fulltextTokens: [],
|
||||
@@ -228,7 +228,7 @@ describe("Invalid expressions", () => {
|
||||
{ token: "=", inQuotes: false },
|
||||
{ token: "#second", inQuotes: true },
|
||||
],
|
||||
parsingContext: new ParsingContext()
|
||||
searchContext: new SearchContext()
|
||||
});
|
||||
|
||||
expect(rootExp.constructor.name).toEqual("LabelComparisonExp");
|
||||
|
||||
+72
-72
@@ -1,7 +1,7 @@
|
||||
const searchService = require('../../src/services/search/services/search.js');
|
||||
const Note = require('../../src/services/note_cache/entities/note.js');
|
||||
const Branch = require('../../src/services/note_cache/entities/branch.js');
|
||||
const ParsingContext = require('../../src/services/search/parsing_context.js');
|
||||
const SearchContext = require('../../src/services/search/search_context.js');
|
||||
const dateUtils = require('../../src/services/date_utils.js');
|
||||
const noteCache = require('../../src/services/note_cache/note_cache.js');
|
||||
const {NoteBuilder, findNoteByTitle, note} = require('./note_cache_mocking.js');
|
||||
@@ -22,8 +22,8 @@ describe("Search", () => {
|
||||
.child(note("Austria"))
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchResults = searchService.findNotesWithQuery('europe austria', parsingContext);
|
||||
const searchContext = new SearchContext();
|
||||
const searchResults = searchService.findNotesWithQuery('europe austria', searchContext);
|
||||
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||
@@ -39,13 +39,13 @@ describe("Search", () => {
|
||||
.child(vienna
|
||||
.label('inhabitants', '1888776'));
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
let searchResults = searchService.findNotesWithQuery('capital', parsingContext);
|
||||
const searchContext = new SearchContext();
|
||||
let searchResults = searchService.findNotesWithQuery('capital', searchContext);
|
||||
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('inhabitants', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('inhabitants', searchContext);
|
||||
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Vienna")).toBeTruthy();
|
||||
@@ -56,18 +56,18 @@ describe("Search", () => {
|
||||
.child(note("Effective Java", 'book', ''))
|
||||
.child(note("Hello World.java", 'code', 'text/x-java'));
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
let searchResults = searchService.findNotesWithQuery('book', parsingContext);
|
||||
const searchContext = new SearchContext();
|
||||
let searchResults = searchService.findNotesWithQuery('book', searchContext);
|
||||
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Effective Java")).toBeTruthy();
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('text', parsingContext); // should match mime
|
||||
searchResults = searchService.findNotesWithQuery('text', searchContext); // should match mime
|
||||
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Hello World.java")).toBeTruthy();
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('java', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('java', searchContext);
|
||||
|
||||
expect(searchResults.length).toEqual(2);
|
||||
});
|
||||
@@ -78,8 +78,8 @@ describe("Search", () => {
|
||||
.child(note("Austria"))
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchResults = searchService.findNotesWithQuery('europe', parsingContext);
|
||||
const searchContext = new SearchContext();
|
||||
const searchResults = searchService.findNotesWithQuery('europe', searchContext);
|
||||
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy();
|
||||
@@ -92,9 +92,9 @@ describe("Search", () => {
|
||||
.label('capital', 'Vienna'))
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
const searchResults = searchService.findNotesWithQuery('Vienna', parsingContext);
|
||||
const searchResults = searchService.findNotesWithQuery('Vienna', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||
});
|
||||
@@ -108,9 +108,9 @@ describe("Search", () => {
|
||||
.label('capital', 'Prague'))
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('#capital=Vienna', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('#capital=Vienna', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||
});
|
||||
@@ -124,9 +124,9 @@ describe("Search", () => {
|
||||
.label('capital', 'Prague'))
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('# note.labels.capital=Prague', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('# note.labels.capital=Prague', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||
});
|
||||
@@ -141,9 +141,9 @@ describe("Search", () => {
|
||||
.label('population', '10650000'))
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
const searchResults = searchService.findNotesWithQuery('#country #population >= 10000000', parsingContext);
|
||||
const searchResults = searchService.findNotesWithQuery('#country #population >= 10000000', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||
});
|
||||
@@ -162,13 +162,13 @@ describe("Search", () => {
|
||||
.label('established', '1920-06-04'))
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('#established <= "1955-01-01"', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('#established <= "1955-01-01"', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Hungary")).toBeTruthy();
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('#established > "1955-01-01"', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('#established > "1955-01-01"', searchContext);
|
||||
expect(searchResults.length).toEqual(2);
|
||||
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||
@@ -185,10 +185,10 @@ describe("Search", () => {
|
||||
.label('dateTime', dateUtils.localNowDateTime())
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
function test(query, expectedResultCount) {
|
||||
const searchResults = searchService.findNotesWithQuery(query, parsingContext);
|
||||
const searchResults = searchService.findNotesWithQuery(query, searchContext);
|
||||
expect(searchResults.length).toEqual(expectedResultCount);
|
||||
|
||||
if (expectedResultCount === 1) {
|
||||
@@ -238,9 +238,9 @@ describe("Search", () => {
|
||||
.label('languageFamily', 'finnougric'))
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
const searchResults = searchService.findNotesWithQuery('#languageFamily = slavic OR #languageFamily = germanic', parsingContext);
|
||||
const searchResults = searchService.findNotesWithQuery('#languageFamily = slavic OR #languageFamily = germanic', searchContext);
|
||||
expect(searchResults.length).toEqual(2);
|
||||
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||
@@ -255,20 +255,20 @@ describe("Search", () => {
|
||||
.child(note("Czech Republic")
|
||||
.label('languageFamily', 'slavic')));
|
||||
|
||||
let parsingContext = new ParsingContext({fuzzyAttributeSearch: false});
|
||||
let searchContext = new SearchContext({fuzzyAttributeSearch: false});
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('#language', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('#language', searchContext);
|
||||
expect(searchResults.length).toEqual(0);
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('#languageFamily=ger', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('#languageFamily=ger', searchContext);
|
||||
expect(searchResults.length).toEqual(0);
|
||||
|
||||
parsingContext = new ParsingContext({fuzzyAttributeSearch: true});
|
||||
searchContext = new SearchContext({fuzzyAttributeSearch: true});
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('#language', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('#language', searchContext);
|
||||
expect(searchResults.length).toEqual(2);
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('#languageFamily=ger', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('#languageFamily=ger', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||
});
|
||||
@@ -279,9 +279,9 @@ describe("Search", () => {
|
||||
.child(note("Austria"))
|
||||
.child(note("Czech Republic")));
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
const searchResults = searchService.findNotesWithQuery('# note.title =* czech', parsingContext);
|
||||
const searchResults = searchService.findNotesWithQuery('# note.title =* czech', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||
});
|
||||
@@ -296,18 +296,18 @@ describe("Search", () => {
|
||||
.child(note("Asia")
|
||||
.child(note('Taiwan')));
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe', searchContext);
|
||||
expect(searchResults.length).toEqual(2);
|
||||
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Asia', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Asia', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Taiwan")).toBeTruthy();
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.parents.title = Europe', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.parents.title = Europe', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Prague")).toBeTruthy();
|
||||
});
|
||||
@@ -324,13 +324,13 @@ describe("Search", () => {
|
||||
.child(note('Taipei').label('city')))
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('#city AND note.ancestors.title = Europe', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('#city AND note.ancestors.title = Europe', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Prague")).toBeTruthy();
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('#city AND note.ancestors.title = Asia', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('#city AND note.ancestors.title = Asia', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Taipei")).toBeTruthy();
|
||||
});
|
||||
@@ -345,18 +345,18 @@ describe("Search", () => {
|
||||
.child(note("Oceania")
|
||||
.child(note('Australia')));
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('# note.children.title =* Aust', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('# note.children.title =* Aust', searchContext);
|
||||
expect(searchResults.length).toEqual(2);
|
||||
expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy();
|
||||
expect(findNoteByTitle(searchResults, "Oceania")).toBeTruthy();
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('# note.children.title =* Aust AND note.children.title *= republic', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('# note.children.title =* Aust AND note.children.title *= republic', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy();
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('# note.children.children.title = Prague', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('# note.children.children.title = Prague', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Europe")).toBeTruthy();
|
||||
});
|
||||
@@ -375,13 +375,13 @@ describe("Search", () => {
|
||||
.relation('neighbor', portugal.note))
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('# ~neighbor.title = Austria', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('# ~neighbor.title = Austria', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('# ~neighbor.title = Portugal', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('# ~neighbor.title = Portugal', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Spain")).toBeTruthy();
|
||||
});
|
||||
@@ -400,9 +400,9 @@ describe("Search", () => {
|
||||
.relation('neighbor', portugal.note))
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
const searchResults = searchService.findNotesWithQuery('# note.relations.neighbor.title = Austria', parsingContext);
|
||||
const searchResults = searchService.findNotesWithQuery('# note.relations.neighbor.title = Austria', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||
});
|
||||
@@ -426,13 +426,13 @@ describe("Search", () => {
|
||||
.child(ukraine)
|
||||
);
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('# note.relations.neighbor.relations.neighbor.title = Italy', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('# note.relations.neighbor.relations.neighbor.title = Italy', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('# note.relations.neighbor.relations.neighbor.title = Ukraine', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('# note.relations.neighbor.relations.neighbor.title = Ukraine', searchContext);
|
||||
expect(searchResults.length).toEqual(2);
|
||||
expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||
expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||
@@ -463,10 +463,10 @@ describe("Search", () => {
|
||||
austria.note.utcDateModified = '2020-05-14 11:11:42.001Z';
|
||||
austria.note.contentLength = 1001;
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
function test(propertyName, value, expectedResultCount) {
|
||||
const searchResults = searchService.findNotesWithQuery(`# note.${propertyName} = ${value}`, parsingContext);
|
||||
const searchResults = searchService.findNotesWithQuery(`# note.${propertyName} = ${value}`, searchContext);
|
||||
expect(searchResults.length).toEqual(expectedResultCount);
|
||||
}
|
||||
|
||||
@@ -520,38 +520,38 @@ describe("Search", () => {
|
||||
.child(austria)
|
||||
.child(italy));
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.title', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.title', searchContext);
|
||||
expect(searchResults.length).toEqual(4);
|
||||
expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Austria");
|
||||
expect(noteCache.notes[searchResults[1].noteId].title).toEqual("Italy");
|
||||
expect(noteCache.notes[searchResults[2].noteId].title).toEqual("Slovakia");
|
||||
expect(noteCache.notes[searchResults[3].noteId].title).toEqual("Ukraine");
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.labels.capital', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.labels.capital', searchContext);
|
||||
expect(searchResults.length).toEqual(4);
|
||||
expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Slovakia");
|
||||
expect(noteCache.notes[searchResults[1].noteId].title).toEqual("Ukraine");
|
||||
expect(noteCache.notes[searchResults[2].noteId].title).toEqual("Italy");
|
||||
expect(noteCache.notes[searchResults[3].noteId].title).toEqual("Austria");
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.labels.capital DESC', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.labels.capital DESC', searchContext);
|
||||
expect(searchResults.length).toEqual(4);
|
||||
expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Austria");
|
||||
expect(noteCache.notes[searchResults[1].noteId].title).toEqual("Italy");
|
||||
expect(noteCache.notes[searchResults[2].noteId].title).toEqual("Ukraine");
|
||||
expect(noteCache.notes[searchResults[3].noteId].title).toEqual("Slovakia");
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.labels.capital DESC limit 2', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy note.labels.capital DESC limit 2', searchContext);
|
||||
expect(searchResults.length).toEqual(2);
|
||||
expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Austria");
|
||||
expect(noteCache.notes[searchResults[1].noteId].title).toEqual("Italy");
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy #capital DESC limit 0', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy #capital DESC limit 0', searchContext);
|
||||
expect(searchResults.length).toEqual(0);
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy #capital DESC limit 1000', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('# note.parents.title = Europe orderBy #capital DESC limit 1000', searchContext);
|
||||
expect(searchResults.length).toEqual(4);
|
||||
});
|
||||
|
||||
@@ -564,13 +564,13 @@ describe("Search", () => {
|
||||
.child(slovakia)
|
||||
.child(italy));
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('# not(#capital) and note.noteId != root', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('# not(#capital) and note.noteId != root', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Europe");
|
||||
|
||||
searchResults = searchService.findNotesWithQuery('#!capital and note.noteId != root', parsingContext);
|
||||
searchResults = searchService.findNotesWithQuery('#!capital and note.noteId != root', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Europe");
|
||||
});
|
||||
@@ -584,9 +584,9 @@ describe("Search", () => {
|
||||
.child(slovakia)
|
||||
.child(italy));
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('# note.text *=* rati and note.noteId != root', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('# note.text *=* rati and note.noteId != root', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Slovakia");
|
||||
});
|
||||
@@ -601,9 +601,9 @@ describe("Search", () => {
|
||||
.child(note('Post Y')))
|
||||
.child(note ('Reddit is bad'));
|
||||
|
||||
const parsingContext = new ParsingContext();
|
||||
const searchContext = new SearchContext();
|
||||
|
||||
let searchResults = searchService.findNotesWithQuery('reddit', parsingContext);
|
||||
let searchResults = searchService.findNotesWithQuery('reddit', searchContext);
|
||||
expect(searchResults.length).toEqual(1);
|
||||
expect(noteCache.notes[searchResults[0].noteId].title).toEqual("Reddit is bad");
|
||||
});
|
||||
@@ -624,9 +624,9 @@ describe("Search", () => {
|
||||
// .label('largestCity', 'Prague'))
|
||||
// );
|
||||
//
|
||||
// const parsingContext = new ParsingContext();
|
||||
// const searchContext = new SearchContext();
|
||||
//
|
||||
// const searchResults = searchService.findNotesWithQuery('#capital = #largestCity', parsingContext);
|
||||
// const searchResults = searchService.findNotesWithQuery('#capital = #largestCity', searchContext);
|
||||
// expect(searchResults.length).toEqual(2);
|
||||
// expect(findNoteByTitle(searchResults, "Czech Republic")).toBeTruthy();
|
||||
// expect(findNoteByTitle(searchResults, "Austria")).toBeTruthy();
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
|
||||
const Entity = require('./entity');
|
||||
const dateUtils = require('../services/date_utils');
|
||||
const sql = require('../services/sql');
|
||||
const promotedAttributeDefinitionParser = require("../services/promoted_attribute_definition_parser");
|
||||
|
||||
/**
|
||||
* Attribute is key value pair owned by a note.
|
||||
@@ -30,14 +32,6 @@ class Attribute extends Entity {
|
||||
super(row);
|
||||
|
||||
this.isInheritable = !!this.isInheritable;
|
||||
|
||||
if (this.isDefinition()) {
|
||||
try {
|
||||
this.value = JSON.parse(this.value);
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +60,21 @@ class Attribute extends Entity {
|
||||
* @return {boolean}
|
||||
*/
|
||||
isDefinition() {
|
||||
return this.type === 'label-definition' || this.type === 'relation-definition';
|
||||
return this.type === 'label' && (this.name.startsWith('label:') || this.name.startsWith('relation:'));
|
||||
}
|
||||
|
||||
getDefinition() {
|
||||
return promotedAttributeDefinitionParser.parse(this.value);
|
||||
}
|
||||
|
||||
getDefinedName() {
|
||||
if (this.type === 'label' && this.name.startsWith('label:')) {
|
||||
return this.name.substr(6);
|
||||
} else if (this.type === 'label' && this.name.startsWith('relation:')) {
|
||||
return this.name.substr(9);
|
||||
} else {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
beforeSaving() {
|
||||
|
||||
+14
-21
@@ -9,9 +9,7 @@ const dateUtils = require('../services/date_utils');
|
||||
const entityChangesService = require('../services/entity_changes.js');
|
||||
|
||||
const LABEL = 'label';
|
||||
const LABEL_DEFINITION = 'label-definition';
|
||||
const RELATION = 'relation';
|
||||
const RELATION_DEFINITION = 'relation-definition';
|
||||
|
||||
/**
|
||||
* This represents a Note which is a central object in the Trilium Notes project.
|
||||
@@ -105,6 +103,7 @@ class Note extends Entity {
|
||||
}
|
||||
}
|
||||
|
||||
/** @returns {{contentLength, dateModified, utcDateModified}} */
|
||||
getContentMetadata() {
|
||||
return sql.getRow(`
|
||||
SELECT
|
||||
@@ -301,14 +300,6 @@ class Note extends Entity {
|
||||
return this.getOwnedAttributes(LABEL, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - label name to filter
|
||||
* @returns {Attribute[]} all note's label definitions, including inherited ones
|
||||
*/
|
||||
getLabelDefinitions(name) {
|
||||
return this.getAttributes(LABEL_DEFINITION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - relation name to filter
|
||||
* @returns {Attribute[]} all note's relations (attributes with type relation), including inherited ones
|
||||
@@ -340,14 +331,6 @@ class Note extends Entity {
|
||||
return targets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - relation name to filter
|
||||
* @returns {Attribute[]} all note's relation definitions including inherited ones
|
||||
*/
|
||||
getRelationDefinitions(name) {
|
||||
return this.getAttributes(RELATION_DEFINITION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear note's attributes cache to force fresh reload for next attribute request.
|
||||
* Cache is note instance scoped.
|
||||
@@ -397,15 +380,15 @@ class Note extends Entity {
|
||||
return firstDefinitionIndex === index;
|
||||
}
|
||||
else {
|
||||
const definitionAttr = attributes.find(el => el.type === attr.type + '-definition' && el.name === attr.name);
|
||||
const definitionAttr = attributes.find(el => el.type === 'label' && el.name === attr.type + ':' + attr.name);
|
||||
|
||||
if (!definitionAttr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const definition = definitionAttr.value;
|
||||
const definition = definitionAttr.getDefinition();
|
||||
|
||||
if (definition.multiplicityType === 'multi') {
|
||||
if (definition.multiplicity === 'multi') {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@@ -885,6 +868,16 @@ class Note extends Entity {
|
||||
return notePaths;
|
||||
}
|
||||
|
||||
getRelationDefinitions() {
|
||||
return this.getLabels()
|
||||
.filter(l => l.name.startsWith("relation:"));
|
||||
}
|
||||
|
||||
getLabelDefinitions() {
|
||||
return this.getLabels()
|
||||
.filter(l => l.name.startsWith("relation:"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ancestorNoteId
|
||||
* @return {boolean} - true if ancestorNoteId occurs in at least one of the note's paths
|
||||
|
||||
@@ -33,6 +33,7 @@ class NoteRevision extends Entity {
|
||||
constructor(row) {
|
||||
super(row);
|
||||
|
||||
this.isErased = !!this.isErased;
|
||||
this.isProtected = !!this.isProtected;
|
||||
|
||||
if (this.isProtected) {
|
||||
|
||||
@@ -3,9 +3,7 @@ import Attribute from './attribute.js';
|
||||
import noteAttributeCache from "../services/note_attribute_cache.js";
|
||||
|
||||
const LABEL = 'label';
|
||||
const LABEL_DEFINITION = 'label-definition';
|
||||
const RELATION = 'relation';
|
||||
const RELATION_DEFINITION = 'relation-definition';
|
||||
|
||||
/**
|
||||
* FIXME: since there's no "full note" anymore we can rename this to Note
|
||||
@@ -74,6 +72,10 @@ class NoteShort {
|
||||
|
||||
this.childToBranch[childNoteId] = branchId;
|
||||
|
||||
this.sortChildren();
|
||||
}
|
||||
|
||||
sortChildren() {
|
||||
const branchIdPos = {};
|
||||
|
||||
for (const branchId of Object.values(this.childToBranch)) {
|
||||
@@ -243,14 +245,6 @@ class NoteShort {
|
||||
return this.getAttributes(LABEL, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - label name to filter
|
||||
* @returns {Attribute[]} all note's label definitions, including inherited ones
|
||||
*/
|
||||
getLabelDefinitions(name) {
|
||||
return this.getAttributes(LABEL_DEFINITION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - relation name to filter
|
||||
* @returns {Attribute[]} all note's relations (attributes with type relation), including inherited ones
|
||||
@@ -267,14 +261,6 @@ class NoteShort {
|
||||
return this.getAttributes(RELATION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - relation name to filter
|
||||
* @returns {Attribute[]} all note's relation definitions including inherited ones
|
||||
*/
|
||||
getRelationDefinitions(name) {
|
||||
return this.getAttributes(RELATION_DEFINITION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
|
||||
@@ -20,7 +20,7 @@ import NoteInfoWidget from "../widgets/collapsible_widgets/note_info.js";
|
||||
import CalendarWidget from "../widgets/collapsible_widgets/calendar.js";
|
||||
import LinkMapWidget from "../widgets/collapsible_widgets/link_map.js";
|
||||
import NoteRevisionsWidget from "../widgets/collapsible_widgets/note_revisions.js";
|
||||
import SimilarNotesWidget from "../widgets/collapsible_widgets/similar_notes.js";
|
||||
import SimilarNotesWidget from "../widgets/similar_notes.js";
|
||||
import WhatLinksHereWidget from "../widgets/collapsible_widgets/what_links_here.js";
|
||||
import SidePaneToggles from "../widgets/side_pane_toggles.js";
|
||||
import EditedNotesWidget from "../widgets/collapsible_widgets/edited_notes.js";
|
||||
@@ -138,6 +138,7 @@ export default class DesktopMainWindowLayout {
|
||||
)
|
||||
.child(new TabCachingWidget(() => new AttributeListWidget()))
|
||||
.child(new TabCachingWidget(() => new NoteDetailWidget()))
|
||||
.child(new TabCachingWidget(() => new SimilarNotesWidget()))
|
||||
.child(...this.customWidgets.get('center-pane'))
|
||||
)
|
||||
.child(new SidePaneContainer('right')
|
||||
@@ -148,7 +149,6 @@ export default class DesktopMainWindowLayout {
|
||||
.child(new TabCachingWidget(() => new EditedNotesWidget()))
|
||||
.child(new TabCachingWidget(() => new LinkMapWidget()))
|
||||
.child(new TabCachingWidget(() => new NoteRevisionsWidget()))
|
||||
.child(new TabCachingWidget(() => new SimilarNotesWidget()))
|
||||
.child(new TabCachingWidget(() => new WhatLinksHereWidget()))
|
||||
.child(...this.customWidgets.get('right-pane'))
|
||||
)
|
||||
|
||||
@@ -76,13 +76,13 @@ export default class MobileLayout {
|
||||
.child(new NoteTreeWidget("main").cssBlock(FANCYTREE_CSS)))
|
||||
.child(new ScreenContainer("detail", "column")
|
||||
.class("d-sm-flex d-md-flex d-lg-flex d-xl-flex col-12 col-sm-7 col-md-8 col-lg-8")
|
||||
.child(new FlexContainer('row')
|
||||
.child(new FlexContainer('row').overflowing()
|
||||
.css('font-size', 'larger')
|
||||
.css('align-items', 'center')
|
||||
.child(new MobileDetailMenuWidget())
|
||||
.child(new NoteTitleWidget()
|
||||
.css('padding', '10px')
|
||||
.css('font-size', 'larger'))
|
||||
.child(new NoteTitleWidget())
|
||||
.child(new CloseDetailButtonWidget()))
|
||||
.child(new NoteDetailWidget()
|
||||
.css('padding', '5px 20px 10px 0')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,32 @@
|
||||
import ws from "./ws.js";
|
||||
import linkService from "./link.js";
|
||||
import treeCache from "./tree_cache.js";
|
||||
|
||||
function renderAttribute(attribute, $container, renderIsInheritable) {
|
||||
async function renderAttribute(attribute, renderIsInheritable) {
|
||||
const isInheritable = renderIsInheritable && attribute.isInheritable ? `(inheritable)` : '';
|
||||
const $attr = $("<span>");
|
||||
|
||||
if (attribute.type === 'label') {
|
||||
$container.append(document.createTextNode('#' + attribute.name + isInheritable));
|
||||
$attr.append(document.createTextNode('#' + attribute.name + isInheritable));
|
||||
|
||||
if (attribute.value) {
|
||||
$container.append('=');
|
||||
$container.append(document.createTextNode(formatValue(attribute.value)));
|
||||
$attr.append('=');
|
||||
$attr.append(document.createTextNode(formatValue(attribute.value)));
|
||||
}
|
||||
} else if (attribute.type === 'relation') {
|
||||
if (attribute.isAutoLink) {
|
||||
return;
|
||||
return $attr;
|
||||
}
|
||||
|
||||
// when the relation has just been created then it might not have a value
|
||||
if (attribute.value) {
|
||||
$container.append(document.createTextNode('~' + attribute.name + isInheritable + "="));
|
||||
$container.append(createNoteLink(attribute.value));
|
||||
$attr.append(document.createTextNode('~' + attribute.name + isInheritable + "="));
|
||||
$attr.append(await createNoteLink(attribute.value));
|
||||
}
|
||||
} else {
|
||||
ws.logError("Unknown attr type: " + attribute.type);
|
||||
}
|
||||
|
||||
return $attr;
|
||||
}
|
||||
|
||||
function formatValue(val) {
|
||||
@@ -44,18 +47,39 @@ function formatValue(val) {
|
||||
}
|
||||
}
|
||||
|
||||
function createNoteLink(noteId) {
|
||||
const $link = $("<a>", {
|
||||
async function createNoteLink(noteId) {
|
||||
const note = await treeCache.getNote(noteId);
|
||||
|
||||
if (!note) {
|
||||
return;
|
||||
}
|
||||
|
||||
return $("<a>", {
|
||||
href: '#' + noteId,
|
||||
class: 'reference-link',
|
||||
'data-note-path': noteId
|
||||
});
|
||||
})
|
||||
.text(note.title);
|
||||
}
|
||||
|
||||
linkService.loadReferenceLinkTitle(noteId, $link);
|
||||
async function renderAttributes(attributes, renderIsInheritable) {
|
||||
const $container = $("<span>");
|
||||
|
||||
return $link;
|
||||
for (let i = 0; i < attributes.length; i++) {
|
||||
const attribute = attributes[i];
|
||||
|
||||
const $attr = await renderAttribute(attribute, renderIsInheritable);
|
||||
$container.append($attr.html()); // .html() to get only inner HTML, we don't want any spans
|
||||
|
||||
if (i < attributes.length - 1) {
|
||||
$container.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
export default {
|
||||
renderAttribute
|
||||
renderAttribute,
|
||||
renderAttributes
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ export default class Entrypoints extends Component {
|
||||
}
|
||||
|
||||
async searchForResultsCommand({searchText}) {
|
||||
const response = await server.get('search/' + encodeURIComponent(searchText));
|
||||
const response = await server.get('search/' + encodeURIComponent(searchText) + '?includeNoteContent=true&excludeArchived=true&fuzzyAttributeSearch=false');
|
||||
|
||||
if (!response.success) {
|
||||
toastService.showError("Search failed.", 3000);
|
||||
|
||||
@@ -87,7 +87,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
||||
* @param {ToolbarButtonOptions} opts
|
||||
*/
|
||||
this.addButtonToToolbar = opts => {
|
||||
const buttonId = "toolbar-button-" + opts.title.replace(/[^a-zA-Z0-9]/g, "-");
|
||||
const buttonId = "toolbar-button-" + opts.title.replace(/\s/g, "-");
|
||||
|
||||
const button = $('<button>')
|
||||
.addClass("btn btn-sm")
|
||||
@@ -169,7 +169,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
||||
|
||||
/**
|
||||
* This is a powerful search method - you can search by attributes and their values, e.g.:
|
||||
* "@dateModified =* MONTH AND @log". See full documentation for all options at: https://github.com/zadam/trilium/wiki/Search
|
||||
* "#dateModified =* MONTH AND #log". See full documentation for all options at: https://github.com/zadam/trilium/wiki/Search
|
||||
*
|
||||
* @method
|
||||
* @param {string} searchString
|
||||
@@ -185,7 +185,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
||||
|
||||
/**
|
||||
* This is a powerful search method - you can search by attributes and their values, e.g.:
|
||||
* "@dateModified =* MONTH AND @log". See full documentation for all options at: https://github.com/zadam/trilium/wiki/Search
|
||||
* "#dateModified =* MONTH AND #log". See full documentation for all options at: https://github.com/zadam/trilium/wiki/Search
|
||||
*
|
||||
* @method
|
||||
* @param {string} searchString
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import options from './options.js';
|
||||
import appContext from "./app_context.js";
|
||||
import treeService from "./tree.js";
|
||||
import treeCache from "./tree_cache.js";
|
||||
|
||||
function getHoistedNoteId() {
|
||||
return options.get('hoistedNoteId');
|
||||
@@ -9,6 +10,8 @@ function getHoistedNoteId() {
|
||||
async function setHoistedNoteId(noteId) {
|
||||
await options.save('hoistedNoteId', noteId);
|
||||
|
||||
await treeCache.loadInitialTree();
|
||||
|
||||
// FIXME - just use option load event
|
||||
appContext.triggerEvent('hoistedNoteChanged', {noteId});
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import treeService from "./tree.js";
|
||||
import linkService from "./link.js";
|
||||
import treeCache from "./tree_cache.js";
|
||||
import utils from "./utils.js";
|
||||
import attributeRenderer from "./attribute_renderer.js";
|
||||
|
||||
function setupGlobalTooltip() {
|
||||
$(document).on("mouseenter", "a", mouseEnterHandler);
|
||||
@@ -82,51 +83,21 @@ async function renderTooltip(note, noteComplement) {
|
||||
return '<div>Note has been deleted.</div>';
|
||||
}
|
||||
|
||||
const attributes = note.getAttributes();
|
||||
const someNotePath = treeService.getSomeNotePath(note);
|
||||
|
||||
let content = '';
|
||||
if (!someNotePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const promoted = attributes
|
||||
.filter(attr => attr.type === 'label-definition' || attr.type === 'relation-definition')
|
||||
.filter(attr => !attr.name.startsWith("child:"))
|
||||
.filter(attr => {
|
||||
const json = attr.jsonValue;
|
||||
let content = $("<h5>").text(await treeService.getNotePathTitle(someNotePath)).prop('outerHTML');
|
||||
|
||||
return json && json.isPromoted;
|
||||
});
|
||||
const attributes = note.getAttributes()
|
||||
.filter(attr => !attr.isDefinition());
|
||||
|
||||
if (promoted.length > 0) {
|
||||
const $table = $("<table>").addClass("promoted-attributes-in-tooltip");
|
||||
|
||||
for (const definitionAttr of promoted) {
|
||||
const definitionType = definitionAttr.type;
|
||||
const valueType = definitionType.substr(0, definitionType.length - 11);
|
||||
|
||||
let valueAttrs = attributes.filter(el => el.name === definitionAttr.name && el.type === valueType);
|
||||
|
||||
for (const valueAttr of valueAttrs) {
|
||||
if (!valueAttr.value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let $value = "";
|
||||
|
||||
if (valueType === 'label') {
|
||||
$value = $("<td>").text(valueAttr.value);
|
||||
}
|
||||
else if (valueType === 'relation' && valueAttr.value) {
|
||||
$value = $("<td>").append(await linkService.createNoteLink(valueAttr.value));
|
||||
}
|
||||
|
||||
const $row = $("<tr>")
|
||||
.append($("<th>").text(definitionAttr.name))
|
||||
.append($value);
|
||||
|
||||
$table.append($row);
|
||||
}
|
||||
}
|
||||
|
||||
content += $table.prop('outerHTML');
|
||||
if (attributes.length > 0) {
|
||||
content += '<div class="tooltip-attributes"><strong>Attributes: </strong> '
|
||||
+ (await attributeRenderer.renderAttributes(attributes)).html()
|
||||
+ '</div>'
|
||||
}
|
||||
|
||||
if (note.type === 'text' && !utils.isHtmlEmpty(noteComplement.content)) {
|
||||
|
||||
@@ -158,6 +158,12 @@ function getNoteIdFromNotePath(notePath) {
|
||||
return lastSegment.split("-")[0];
|
||||
}
|
||||
|
||||
async function getBranchIdFromNotePath(notePath) {
|
||||
const {noteId, parentNoteId} = getNoteIdAndParentIdFromNotePath(notePath);
|
||||
|
||||
return await treeCache.getBranchId(parentNoteId, noteId);
|
||||
}
|
||||
|
||||
function getNoteIdAndParentIdFromNotePath(notePath) {
|
||||
if (notePath === 'root') {
|
||||
return {
|
||||
@@ -185,7 +191,7 @@ function getNoteIdAndParentIdFromNotePath(notePath) {
|
||||
return {
|
||||
parentNoteId,
|
||||
noteId
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getNotePath(node) {
|
||||
@@ -286,6 +292,7 @@ export default {
|
||||
getNotePath,
|
||||
getNoteIdFromNotePath,
|
||||
getNoteIdAndParentIdFromNotePath,
|
||||
getBranchIdFromNotePath,
|
||||
getNoteTitle,
|
||||
getNotePathTitle,
|
||||
getHashValueFromAddress,
|
||||
|
||||
@@ -276,6 +276,10 @@ class TreeCache {
|
||||
}
|
||||
|
||||
async getBranchId(parentNoteId, childNoteId) {
|
||||
if (childNoteId === 'root') {
|
||||
return 'root';
|
||||
}
|
||||
|
||||
const child = await this.getNote(childNoteId);
|
||||
|
||||
if (!child) {
|
||||
|
||||
@@ -3,7 +3,6 @@ import treeCache from "./tree_cache.js";
|
||||
import hoistedNoteService from './hoisted_note.js';
|
||||
import clipboard from './clipboard.js';
|
||||
import protectedSessionHolder from "./protected_session_holder.js";
|
||||
import appContext from "./app_context.js";
|
||||
import noteCreateService from "./note_create.js";
|
||||
import contextMenu from "./context_menu.js";
|
||||
|
||||
|
||||
@@ -150,15 +150,21 @@ async function consumeSyncData() {
|
||||
const nonProcessedSyncRows = allSyncRows.filter(sync => !processedEntityChangeIds.has(sync.id));
|
||||
|
||||
try {
|
||||
await utils.timeLimit(processSyncRows(nonProcessedSyncRows), 5000);
|
||||
await utils.timeLimit(processSyncRows(nonProcessedSyncRows), 30000);
|
||||
}
|
||||
catch (e) {
|
||||
logError(`Encountered error ${e.message}: ${e.stack}, reloading frontend.`);
|
||||
|
||||
// if there's an error in updating the frontend then the easy option to recover is to reload the frontend completely
|
||||
if (!glob.isDev) {
|
||||
if (!glob.isDev && !options.is('debugModeEnabled')) {
|
||||
// if there's an error in updating the frontend then the easy option to recover is to reload the frontend completely
|
||||
|
||||
utils.reloadApp();
|
||||
}
|
||||
else {
|
||||
console.log("nonProcessedSyncRows causing the timeout", nonProcessedSyncRows);
|
||||
|
||||
alert(`Encountered error "${e.message}", check out the console.`);
|
||||
}
|
||||
}
|
||||
|
||||
for (const syncRow of nonProcessedSyncRows) {
|
||||
@@ -306,11 +312,23 @@ async function processSyncRows(syncRows) {
|
||||
}
|
||||
|
||||
for (const sync of syncRows.filter(sync => sync.entityName === 'note_reordering')) {
|
||||
const parentNoteIdsToSort = new Set();
|
||||
|
||||
for (const branchId in sync.positions) {
|
||||
const branch = treeCache.branches[branchId];
|
||||
|
||||
if (branch) {
|
||||
branch.notePosition = sync.positions[branchId];
|
||||
|
||||
parentNoteIdsToSort.add(branch.parentNoteId);
|
||||
}
|
||||
}
|
||||
|
||||
for (const parentNoteId of parentNoteIdsToSort) {
|
||||
const parentNote = treeCache.notes[parentNoteId];
|
||||
|
||||
if (parentNote) {
|
||||
parentNote.sortChildren();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ const TPL = `
|
||||
color: var(--muted-text-color);
|
||||
max-height: 100px;
|
||||
overflow: auto;
|
||||
transition: opacity .1s linear;
|
||||
}
|
||||
|
||||
.save-attributes-button {
|
||||
@@ -307,6 +308,12 @@ export default class AttributeEditorWidget extends TabAwareWidget {
|
||||
await server.put(`notes/${this.noteId}/attributes`, attributes, this.componentId);
|
||||
|
||||
this.$saveAttributesButton.fadeOut();
|
||||
|
||||
// blink the attribute text to give visual hint that save has been executed
|
||||
this.$editor.css('opacity', 0);
|
||||
|
||||
// revert back
|
||||
setTimeout(() => this.$editor.css('opacity', 1), 100);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,19 +472,7 @@ export default class AttributeEditorWidget extends TabAwareWidget {
|
||||
async renderOwnedAttributes(ownedAttributes, saved) {
|
||||
ownedAttributes = ownedAttributes.filter(oa => !oa.isDeleted);
|
||||
|
||||
const $attributesContainer = $("<div>");
|
||||
|
||||
for (let i = 0; i < ownedAttributes.length; i++) {
|
||||
const attribute = ownedAttributes[i];
|
||||
|
||||
attributeRenderer.renderAttribute(attribute, $attributesContainer, true);
|
||||
|
||||
if (i < ownedAttributes.length - 1) {
|
||||
$attributesContainer.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
let htmlAttrs = $attributesContainer.html();
|
||||
let htmlAttrs = (await attributeRenderer.renderAttributes(ownedAttributes, true)).html();
|
||||
|
||||
if (htmlAttrs.length > 0) {
|
||||
htmlAttrs += " ";
|
||||
|
||||
@@ -56,7 +56,7 @@ const TPL = `
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.attr-expander:not(.error):hover hr {
|
||||
.attr-expander:hover hr {
|
||||
border-color: var(--main-text-color);
|
||||
}
|
||||
|
||||
@@ -205,9 +205,9 @@ export default class AttributeListWidget extends TabAwareWidget {
|
||||
return 'attribute' + (number === 1 ? '' : 's');
|
||||
}
|
||||
|
||||
renderInheritedAttributes(attributes, $container) {
|
||||
async renderInheritedAttributes(attributes, $container) {
|
||||
for (const attribute of attributes) {
|
||||
const $span = $("<span>")
|
||||
const $attr = (await attributeRenderer.renderAttribute(attribute, false))
|
||||
.on('click', e => this.attributeDetailWidget.showAttributeDetail({
|
||||
attribute: {
|
||||
noteId: attribute.noteId,
|
||||
@@ -220,9 +220,9 @@ export default class AttributeListWidget extends TabAwareWidget {
|
||||
y: e.pageY
|
||||
}));
|
||||
|
||||
attributeRenderer.renderAttribute(attribute, $span, false);
|
||||
|
||||
$container.append($span);
|
||||
$container
|
||||
.append($attr)
|
||||
.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@ const TPL = `
|
||||
`;
|
||||
|
||||
export default class LinkMapWidget extends CollapsibleWidget {
|
||||
isEnabled() {
|
||||
return super.isEnabled() && !this.note.hasLabel('linkMapWidgetDisabled');
|
||||
}
|
||||
|
||||
get widgetTitle() { return "Link map"; }
|
||||
|
||||
get help() {
|
||||
@@ -105,4 +109,4 @@ export default class LinkMapWidget extends CollapsibleWidget {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,10 @@ const TPL = `
|
||||
`;
|
||||
|
||||
export default class NoteInfoWidget extends CollapsibleWidget {
|
||||
isEnabled() {
|
||||
return super.isEnabled() && !this.note.hasLabel('noteInfoWidgetDisabled');
|
||||
}
|
||||
|
||||
get widgetTitle() { return "Note info"; }
|
||||
|
||||
async doRenderBody() {
|
||||
|
||||
@@ -7,6 +7,10 @@ const TPL = `
|
||||
`;
|
||||
|
||||
class NoteRevisionsWidget extends CollapsibleWidget {
|
||||
isEnabled() {
|
||||
return super.isEnabled() && !this.note.hasLabel('noteRevisionsWidgetDisabled');
|
||||
}
|
||||
|
||||
get widgetTitle() { return "Note revisions"; }
|
||||
|
||||
get help() {
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
import CollapsibleWidget from "../collapsible_widget.js";
|
||||
import linkService from "../../services/link.js";
|
||||
import server from "../../services/server.js";
|
||||
import treeCache from "../../services/tree_cache.js";
|
||||
|
||||
export default class SimilarNotesWidget extends CollapsibleWidget {
|
||||
get widgetTitle() { return "Similar notes"; }
|
||||
|
||||
get help() {
|
||||
return {
|
||||
title: "This list contains notes which might be similar to the current note based on textual similarity of note title."
|
||||
};
|
||||
}
|
||||
|
||||
noteSwitched() {
|
||||
const noteId = this.noteId;
|
||||
|
||||
this.$body.empty();
|
||||
|
||||
// avoid executing this expensive operation multiple times when just going through notes (with keyboard especially)
|
||||
// until the users settles on a note
|
||||
setTimeout(() => {
|
||||
if (this.noteId === noteId) {
|
||||
this.refresh();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
async refreshWithNote(note) {
|
||||
// remember which title was when we found the similar notes
|
||||
this.title = note.title;
|
||||
|
||||
const similarNotes = await server.get('similar-notes/' + this.noteId);
|
||||
|
||||
if (similarNotes.length === 0) {
|
||||
this.$body.text("No similar notes found ...");
|
||||
return;
|
||||
}
|
||||
|
||||
const noteIds = similarNotes.flatMap(note => note.notePath);
|
||||
|
||||
await treeCache.getNotes(noteIds, true); // preload all at once
|
||||
|
||||
const $list = $('<ul>');
|
||||
|
||||
for (const similarNote of similarNotes) {
|
||||
const note = await treeCache.getNote(similarNote.noteId, true);
|
||||
|
||||
if (!note) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const $item = $("<li>")
|
||||
.append(await linkService.createNoteLink(similarNote.notePath.join("/"), {showNotePath: true}));
|
||||
|
||||
$list.append($item);
|
||||
}
|
||||
|
||||
this.$body.empty().append($list);
|
||||
}
|
||||
|
||||
entitiesReloadedEvent({loadResults}) {
|
||||
if (this.note && this.title !== this.note.title) {
|
||||
this.rendered = false;
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,10 @@ import CollapsibleWidget from "../collapsible_widget.js";
|
||||
import linkService from "../../services/link.js";
|
||||
|
||||
export default class WhatLinksHereWidget extends CollapsibleWidget {
|
||||
isEnabled() {
|
||||
return super.isEnabled() && !this.note.hasLabel('whatLinksHereWidgetDisabled');
|
||||
}
|
||||
|
||||
get widgetTitle() { return "What links here"; }
|
||||
|
||||
get help() {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import BasicWidget from "../basic_widget.js";
|
||||
|
||||
const TPL = `
|
||||
<button type="button" class="action-button d-sm-none d-md-none d-lg-none d-xl-none" aria-label="Close">
|
||||
<button type="button" class="action-button d-sm-none d-md-none d-lg-none d-xl-none" aria-label="Close" style="padding-top: 10px;">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>`;
|
||||
|
||||
class CloseDetailButtonWidget extends BasicWidget {
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.overflowing();
|
||||
|
||||
this.$widget.on('click', () => this.triggerCommand('setActiveScreen', {screen:'tree'}));
|
||||
}
|
||||
|
||||
@@ -3,12 +3,14 @@ import appContext from "../../services/app_context.js";
|
||||
import contextMenu from "../../services/context_menu.js";
|
||||
import noteCreateService from "../../services/note_create.js";
|
||||
import branchService from "../../services/branches.js";
|
||||
import treeService from "../../services/tree.js";
|
||||
|
||||
const TPL = `<button type="button" class="action-button bx bx-menu"></button>`;
|
||||
const TPL = `<button type="button" class="action-button bx bx-menu" style="padding-top: 10px;"></button>`;
|
||||
|
||||
class MobileDetailMenuWidget extends BasicWidget {
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.overflowing();
|
||||
|
||||
this.$widget.on("click", async e => {
|
||||
const note = appContext.tabManager.getActiveTabNote();
|
||||
@@ -27,9 +29,15 @@ class MobileDetailMenuWidget extends BasicWidget {
|
||||
noteCreateService.createNote(note.noteId);
|
||||
}
|
||||
else if (command === "delete") {
|
||||
if (await branchService.deleteNotes(note.getBranchIds()[0])) {
|
||||
// move to the tree
|
||||
togglePanes();
|
||||
const notePath = appContext.tabManager.getActiveTabNotePath();
|
||||
const branchId = await treeService.getBranchIdFromNotePath(notePath);
|
||||
|
||||
if (!branchId) {
|
||||
throw new Error(`Cannot get branchId for notePath ${notePath}`);
|
||||
}
|
||||
|
||||
if (await branchService.deleteNotes([branchId])) {
|
||||
this.triggerCommand('setActiveScreen', {screen:'tree'})
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -32,8 +32,9 @@ const WIDGET_TPL = `
|
||||
|
||||
class MobileGlobalButtonsWidget extends BasicWidget {
|
||||
doRender() {
|
||||
return this.$widget = $(WIDGET_TPL);
|
||||
this.$widget = $(WIDGET_TPL);
|
||||
this.overflowing();
|
||||
}
|
||||
}
|
||||
|
||||
export default MobileGlobalButtonsWidget;
|
||||
export default MobileGlobalButtonsWidget;
|
||||
|
||||
@@ -36,6 +36,11 @@ const TPL = `
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.note-path-list {
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="current-path"></div>
|
||||
|
||||
@@ -32,7 +32,7 @@ const TPL = `
|
||||
.tree {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding-bottom: 20px;
|
||||
padding-bottom: 35px;
|
||||
}
|
||||
|
||||
.refresh-search-button {
|
||||
@@ -51,7 +51,7 @@ const TPL = `
|
||||
.tree-settings-button {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 20px;
|
||||
right: 10px;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
@@ -104,11 +104,7 @@ const TPL = `
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
span.fancytree-active:not(.fancytree-focused) .fancytree-title {
|
||||
border-style: dashed !important;
|
||||
}
|
||||
|
||||
span.fancytree-focused .fancytree-title, span.fancytree-focused.fancytree-selected .fancytree-title {
|
||||
span.fancytree-active .fancytree-title, span.fancytree-active.fancytree-selected .fancytree-title {
|
||||
color: var(--active-item-text-color) !important;
|
||||
background-color: var(--active-item-background-color) !important;
|
||||
border-color: var(--main-background-color) !important; /* invisible border */
|
||||
@@ -464,9 +460,11 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
||||
&& node.data.noteId === hoistedNoteService.getHoistedNoteId()
|
||||
&& $span.find('.unhoist-button').length === 0) {
|
||||
|
||||
const unhoistButton = $('<span> (<a class="unhoist-button">unhoist</a>)</span>');
|
||||
const unhoistButton = $('<span class="unhoist-button-wrapper" title="Unhoist current note to show the whole note tree">[<a class="unhoist-button">unhoist</a>]</span>');
|
||||
|
||||
$span.append(unhoistButton);
|
||||
// prepending since appending could push out (when note title is too long)
|
||||
// the button too much to the right so that it's not visible
|
||||
$span.prepend(unhoistButton);
|
||||
}
|
||||
|
||||
const note = await treeCache.getNote(node.data.noteId);
|
||||
@@ -1068,6 +1066,9 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
||||
parentNode.addChildren([this.prepareNode(branch, true)]);
|
||||
|
||||
this.sortChildren(parentNode);
|
||||
|
||||
// this might be a first child which would force an icon change
|
||||
noteIdsToUpdate.add(branch.parentNoteId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,8 @@ export default class NoteTypeWidget extends TabAwareWidget {
|
||||
const noteType = NOTE_TYPES.find(nt => nt.type === type);
|
||||
|
||||
this.save(noteType.type, noteType.mime);
|
||||
|
||||
this.$widget.find('.dropdown-toggle').dropdown('toggle');
|
||||
});
|
||||
|
||||
if (this.note.type === noteType.type) {
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
import linkService from "../services/link.js";
|
||||
import server from "../services/server.js";
|
||||
import treeCache from "../services/tree_cache.js";
|
||||
import TabAwareWidget from "./tab_aware_widget.js";
|
||||
import options from "../services/options.js";
|
||||
|
||||
const TPL = `
|
||||
<div class="similar-notes-widget hide-in-zen-mode">
|
||||
<style>
|
||||
.similar-notes-wrapper {
|
||||
max-height: 75px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.similar-notes-wrapper a {
|
||||
display: inline-block;
|
||||
border: 1px dotted var(--main-border-color);
|
||||
border-radius: 20px;
|
||||
background-color: var(--accented-background-color);
|
||||
padding: 0 10px 0 10px;
|
||||
margin: 0 3px 0 3px;
|
||||
max-width: 10em;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.similar-notes-expander {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
color: var(--muted-text-color);
|
||||
font-size: 90%;
|
||||
m
|
||||
}
|
||||
|
||||
.similar-notes-expander hr {
|
||||
height: 1px;
|
||||
border-color: var(--main-border-color);
|
||||
position: relative;
|
||||
top: 4px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.similar-notes-expander-text {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.similar-notes-expander:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.similar-notes-expander:hover hr {
|
||||
border-color: var(--main-text-color);
|
||||
}
|
||||
|
||||
.similar-notes-expander:hover .similar-notes-expander-text {
|
||||
color: var(--main-text-color);
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="similar-notes-expander">
|
||||
<hr class="w-100">
|
||||
|
||||
<div class="similar-notes-expander-text"
|
||||
title="This list contains notes which might be similar to the current note based on textual similarity of note title, its labels and relations."></div>
|
||||
|
||||
<hr class="w-100">
|
||||
</div>
|
||||
|
||||
<div class="similar-notes-wrapper"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
export default class SimilarNotesWidget extends TabAwareWidget {
|
||||
isEnabled() {
|
||||
return super.isEnabled() && !this.note.hasLabel('similarNotesWidgetDisabled');
|
||||
}
|
||||
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.overflowing();
|
||||
|
||||
this.$similarNotesWrapper = this.$widget.find(".similar-notes-wrapper");
|
||||
this.$similarNotesExpanderText = this.$widget.find(".similar-notes-expander-text");
|
||||
|
||||
this.$expander = this.$widget.find('.similar-notes-expander');
|
||||
this.$expander.on('click', async () => {
|
||||
const collapse = this.$similarNotesWrapper.is(":visible");
|
||||
|
||||
await options.save('similarNotesExpanded', !collapse);
|
||||
|
||||
this.triggerEvent(`similarNotesCollapsedStateChanged`, {collapse});
|
||||
});
|
||||
|
||||
return this.$widget;
|
||||
}
|
||||
|
||||
noteSwitched() {
|
||||
const noteId = this.noteId;
|
||||
|
||||
this.toggleInt(false);
|
||||
this.$similarNotesWrapper.hide(); // we'll open it in refresh() if needed
|
||||
|
||||
// avoid executing this expensive operation multiple times when just going through notes (with keyboard especially)
|
||||
// until the users settles on a note
|
||||
setTimeout(() => {
|
||||
if (this.noteId === noteId) {
|
||||
this.refresh();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
if (!this.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remember which title was when we found the similar notes
|
||||
this.title = this.note.title;
|
||||
|
||||
const similarNotes = await server.get('similar-notes/' + this.noteId);
|
||||
|
||||
this.toggleInt(similarNotes.length > 0);
|
||||
|
||||
if (similarNotes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.is('similarNotesExpanded')) {
|
||||
this.$similarNotesWrapper.show();
|
||||
}
|
||||
|
||||
this.$similarNotesExpanderText.text(`${similarNotes.length} similar note${similarNotes.length === 1 ? '': "s"}`);
|
||||
|
||||
const noteIds = similarNotes.flatMap(note => note.notePath);
|
||||
|
||||
await treeCache.getNotes(noteIds, true); // preload all at once
|
||||
|
||||
const $list = $('<div>');
|
||||
|
||||
for (const similarNote of similarNotes) {
|
||||
const note = await treeCache.getNote(similarNote.noteId, true);
|
||||
|
||||
if (!note) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const $item = (await linkService.createNoteLink(similarNote.notePath.join("/")))
|
||||
.css("font-size", 24 * (1 - 1 / (1 + similarNote.score)));
|
||||
|
||||
$list.append($item);
|
||||
}
|
||||
|
||||
this.$similarNotesWrapper.empty().append($list);
|
||||
}
|
||||
|
||||
entitiesReloadedEvent({loadResults}) {
|
||||
if (this.note && this.title !== this.note.title) {
|
||||
this.rendered = false;
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This event is used to synchronize collapsed state of all the tab-cached widgets since they are all rendered
|
||||
* separately but should behave uniformly for the user.
|
||||
*/
|
||||
similarNotesCollapsedStateChangedEvent({collapse}) {
|
||||
if (collapse) {
|
||||
this.$similarNotesWrapper.slideUp(200);
|
||||
} else {
|
||||
this.$similarNotesWrapper.slideDown(200);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,7 @@ export default class StandardTopWidget extends BasicWidget {
|
||||
this.$leaveProtectedSessionButton = this.$widget.find(".leave-protected-session-button");
|
||||
this.$leaveProtectedSessionButton.on('click', protectedSessionService.leaveProtectedSession);
|
||||
|
||||
return this.$widget
|
||||
return this.$widget;
|
||||
}
|
||||
|
||||
protectedSessionStartedEvent() {
|
||||
|
||||
@@ -18,6 +18,7 @@ const TPL = `
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
font-family: var(--detail-text-font-family);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.note-detail-readonly-text p:first-child, .note-detail-editable-text::before {
|
||||
|
||||
@@ -387,12 +387,19 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
padding: 15px 15px 0 15px;
|
||||
background-color: var(--tooltip-background-color) !important;
|
||||
border: 1px solid var(--main-border-color);
|
||||
border-radius: 5px;
|
||||
text-align: left;
|
||||
color: var(--main-text-color) !important;
|
||||
max-width: 500px;
|
||||
box-shadow: 10px 10px 93px -25px #aaaaaa;
|
||||
}
|
||||
|
||||
.tooltip-attributes {
|
||||
color: var(--muted-text-color);
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.note-tooltip-content {
|
||||
@@ -533,6 +540,11 @@ div[data-notify="container"] {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.unhoist-button-wrapper {
|
||||
position: relative;
|
||||
top: -4px;
|
||||
}
|
||||
|
||||
.unhoist-button {
|
||||
text-decoration: underline !important;
|
||||
color: var(--link-color) !important;
|
||||
@@ -637,7 +649,7 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
|
||||
}
|
||||
|
||||
.component {
|
||||
contain: layout size;
|
||||
contain: size;
|
||||
}
|
||||
|
||||
.toast {
|
||||
@@ -824,7 +836,12 @@ body {
|
||||
}
|
||||
|
||||
.ck.ck-mentions > .ck-list__item {
|
||||
max-width: 600px;
|
||||
max-width: 700px;
|
||||
}
|
||||
|
||||
.ck.ck-mentions > .ck-list__item .ck-button {
|
||||
/* wrap text for very long note path title */
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
ul.fancytree-container li {
|
||||
|
||||
@@ -53,7 +53,7 @@ function addClipping(req) {
|
||||
clippingNote.setLabel('pageUrl', pageUrl);
|
||||
}
|
||||
|
||||
const rewrittenContent = addImagesToNote(images, clippingNote, content);
|
||||
const rewrittenContent = processContent(images, clippingNote, content);
|
||||
|
||||
const existingContent = clippingNote.getContent();
|
||||
|
||||
@@ -85,7 +85,7 @@ function createNote(req) {
|
||||
note.setLabel('pageUrl', pageUrl);
|
||||
}
|
||||
|
||||
const rewrittenContent = addImagesToNote(images, note, content);
|
||||
const rewrittenContent = processContent(images, note, content);
|
||||
|
||||
note.setContent(rewrittenContent);
|
||||
|
||||
@@ -94,8 +94,11 @@ function createNote(req) {
|
||||
};
|
||||
}
|
||||
|
||||
function addImagesToNote(images, note, content) {
|
||||
let rewrittenContent = content;
|
||||
function processContent(images, note, content) {
|
||||
// H1 is not supported so convert it to H2
|
||||
let rewrittenContent = content
|
||||
.replace(/<h1/ig, "<h2")
|
||||
.replace(/<\/h1/ig, "</h2");
|
||||
|
||||
if (images) {
|
||||
for (const {src, dataUrl, imageId} of images) {
|
||||
@@ -113,8 +116,8 @@ function addImagesToNote(images, note, content) {
|
||||
new Attribute({
|
||||
noteId: imageNote.noteId,
|
||||
type: 'label',
|
||||
name: 'hideInAutocomplete'
|
||||
}).save();
|
||||
name: 'archived'
|
||||
}).save(); // so that these image notes don't show up in search / autocomplete
|
||||
|
||||
new Attribute({
|
||||
noteId: note.noteId,
|
||||
|
||||
@@ -86,8 +86,9 @@ function downloadNoteRevision(req, res) {
|
||||
function eraseOneNoteRevision(noteRevision) {
|
||||
noteRevision.isErased = true;
|
||||
noteRevision.title = null;
|
||||
noteRevision.setContent(null);
|
||||
noteRevision.save();
|
||||
|
||||
noteRevision.setContent(null);
|
||||
}
|
||||
|
||||
function eraseAllNoteRevisions(req) {
|
||||
|
||||
@@ -139,7 +139,7 @@ function getRelationMap(req) {
|
||||
for (const note of notes) {
|
||||
resp.noteTitles[note.noteId] = note.title;
|
||||
|
||||
resp.relations = resp.relations.concat((note.getRelations())
|
||||
resp.relations = resp.relations.concat(note.getRelations()
|
||||
.filter(relation => noteIds.includes(relation.value))
|
||||
.map(relation => ({
|
||||
attributeId: relation.attributeId,
|
||||
@@ -149,8 +149,10 @@ function getRelationMap(req) {
|
||||
})));
|
||||
|
||||
for (const relationDefinition of note.getRelationDefinitions()) {
|
||||
if (relationDefinition.value.inverseRelation) {
|
||||
resp.inverseRelations[relationDefinition.name] = relationDefinition.value.inverseRelation;
|
||||
const def = relationDefinition.getDefinition();
|
||||
|
||||
if (def.inverseRelation) {
|
||||
resp.inverseRelations[relationDefinition.getDefinedName()] = def.inverseRelation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,8 @@ const ALLOWED_OPTIONS = new Set([
|
||||
'rightPaneVisible',
|
||||
'nativeTitleBarVisible',
|
||||
'attributeListExpanded',
|
||||
'promotedAttributesExpanded'
|
||||
'promotedAttributesExpanded',
|
||||
'similarNotesExpanded'
|
||||
]);
|
||||
|
||||
function getOptions() {
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
"use strict";
|
||||
|
||||
const repository = require('../../services/repository');
|
||||
const noteCacheService = require('../../services/note_cache/note_cache_service');
|
||||
const SearchContext = require('../../services/search/search_context.js');
|
||||
const log = require('../../services/log');
|
||||
const scriptService = require('../../services/script');
|
||||
const searchService = require('../../services/search/services/search');
|
||||
|
||||
function searchNotes(req) {
|
||||
const {count, results} = searchService.searchTrimmedNotes(req.params.searchString);
|
||||
const searchContext = new SearchContext({
|
||||
includeNoteContent: req.query.includeNoteContent === 'true',
|
||||
excludeArchived: req.query.excludeArchived === 'true',
|
||||
fuzzyAttributeSearch: req.query.fuzzyAttributeSearch === 'true'
|
||||
});
|
||||
|
||||
const {count, results} = searchService.searchTrimmedNotes(req.params.searchString, searchContext);
|
||||
|
||||
try {
|
||||
return {
|
||||
@@ -52,7 +58,13 @@ async function searchFromNote(req) {
|
||||
|
||||
searchResultNoteIds = await searchFromRelation(note, relationName);
|
||||
} else {
|
||||
searchResultNoteIds = searchService.searchNotes(json.searchString)
|
||||
const searchContext = new SearchContext({
|
||||
includeNoteContent: true,
|
||||
excludeArchived: true,
|
||||
fuzzyAttributeSearch: false
|
||||
});
|
||||
|
||||
searchResultNoteIds = searchService.findNotesWithQuery(json.searchString, searchContext)
|
||||
.map(sr => sr.noteId);
|
||||
}
|
||||
}
|
||||
@@ -113,8 +125,14 @@ async function searchFromRelation(note, relationName) {
|
||||
function getRelatedNotes(req) {
|
||||
const attr = req.body;
|
||||
|
||||
const matchingNameAndValue = searchService.searchNotes(formatAttrForSearch(attr, true));
|
||||
const matchingName = searchService.searchNotes(formatAttrForSearch(attr, false));
|
||||
const searchSettings = {
|
||||
includeNoteContent: false,
|
||||
excludeArchived: true,
|
||||
fuzzyAttributeSearch: false
|
||||
};
|
||||
|
||||
const matchingNameAndValue = searchService.findNotesWithQuery(formatAttrForSearch(attr, true), new SearchContext(searchSettings));
|
||||
const matchingName = searchService.findNotesWithQuery(formatAttrForSearch(attr, false), new SearchContext(searchSettings));
|
||||
|
||||
const results = [];
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
const noteCacheService = require('../../services/note_cache/note_cache_service');
|
||||
const similarityService = require('../../services/note_cache/similarity.js');
|
||||
const repository = require('../../services/repository');
|
||||
|
||||
function getSimilarNotes(req) {
|
||||
async function getSimilarNotes(req) {
|
||||
const noteId = req.params.noteId;
|
||||
|
||||
const note = repository.getNote(noteId);
|
||||
@@ -12,10 +12,7 @@ function getSimilarNotes(req) {
|
||||
return [404, `Note ${noteId} not found.`];
|
||||
}
|
||||
|
||||
const results = noteCacheService.findSimilarNotes(noteId);
|
||||
|
||||
return results
|
||||
.filter(note => note.noteId !== noteId);
|
||||
return await similarityService.findSimilarNotes(noteId);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -4,7 +4,7 @@ const build = require('./build');
|
||||
const packageJson = require('../../package');
|
||||
const {TRILIUM_DATA_DIR} = require('./data_dir');
|
||||
|
||||
const APP_DB_VERSION = 167;
|
||||
const APP_DB_VERSION = 169;
|
||||
const SYNC_VERSION = 16;
|
||||
const CLIPPER_PROTOCOL_VERSION = "1.0";
|
||||
|
||||
|
||||
@@ -27,6 +27,11 @@ const BUILTIN_ATTRIBUTES = [
|
||||
{ type: 'label', name: 'customResourceProvider', isDangerous: true },
|
||||
{ type: 'label', name: 'bookZoomLevel', isDangerous: false },
|
||||
{ type: 'label', name: 'widget', isDangerous: true },
|
||||
{ type: 'label', name: 'noteInfoWidgetDisabled' },
|
||||
{ type: 'label', name: 'linkMapWidgetDisabled' },
|
||||
{ type: 'label', name: 'noteRevisionsWidgetDisabled' },
|
||||
{ type: 'label', name: 'whatLinksHereWidgetDisabled' },
|
||||
{ type: 'label', name: 'similarNotesWidgetDisabled' },
|
||||
|
||||
// relation names
|
||||
{ type: 'relation', name: 'runOnNoteCreation', isDangerous: true },
|
||||
|
||||
@@ -11,7 +11,8 @@ const axios = require('axios');
|
||||
const dayjs = require('dayjs');
|
||||
const cloningService = require('./cloning');
|
||||
const appInfo = require('./app_info');
|
||||
const searchService = require('./search/services/search.js');
|
||||
const searchService = require('./search/services/search');
|
||||
const SearchContext = require("./search/search_context.js");
|
||||
|
||||
/**
|
||||
* This is the main backend API interface for scripts. It's published in the local "api" object.
|
||||
@@ -90,10 +91,18 @@ function BackendScriptApi(currentNote, apiParams) {
|
||||
* "#dateModified =* MONTH AND #log". See full documentation for all options at: https://github.com/zadam/trilium/wiki/Search
|
||||
*
|
||||
* @method
|
||||
* @param {string} searchString
|
||||
* @param {string} query
|
||||
* @param {SearchContext} [searchContext]
|
||||
* @returns {Note[]}
|
||||
*/
|
||||
this.searchForNotes = searchService.searchNoteEntities;
|
||||
this.searchForNotes = (query, searchContext) => {
|
||||
searchContext = searchContext || new SearchContext();
|
||||
|
||||
const noteIds = searchService.findNotesWithQuery(query, searchContext)
|
||||
.map(sr => sr.noteId);
|
||||
|
||||
return repository.getNotes(noteIds);
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a powerful search method - you can search by attributes and their values, e.g.:
|
||||
|
||||
@@ -1 +1 @@
|
||||
module.exports = { buildDate:"2020-09-05T23:43:06+02:00", buildRevision: "a7505682eddb754f0ba951716f63f9e9ffe61131" };
|
||||
module.exports = { buildDate:"2020-09-19T23:45:46+02:00", buildRevision: "27052143abdd9c093f46e30ae9eac09eb423b22f" };
|
||||
|
||||
@@ -500,9 +500,7 @@ class ConsistencyChecks {
|
||||
FROM attributes
|
||||
WHERE isDeleted = 0
|
||||
AND type != 'label'
|
||||
AND type != 'label-definition'
|
||||
AND type != 'relation'
|
||||
AND type != 'relation-definition'`,
|
||||
AND type != 'relation'`,
|
||||
({attributeId, type}) => {
|
||||
if (this.autoFix) {
|
||||
const attribute = repository.getAttribute(attributeId);
|
||||
|
||||
@@ -250,14 +250,14 @@ function importEnex(taskContext, file, parentNote) {
|
||||
}
|
||||
|
||||
const createFileNote = () => {
|
||||
const resourceNote = (noteService.createNewNote({
|
||||
const resourceNote = noteService.createNewNote({
|
||||
parentNoteId: noteEntity.noteId,
|
||||
title: resource.title,
|
||||
content: resource.content,
|
||||
type: 'file',
|
||||
mime: resource.mime,
|
||||
isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable(),
|
||||
})).note;
|
||||
}).note;
|
||||
|
||||
for (const attr of resource.attributes) {
|
||||
noteEntity.addAttribute(attr.type, attr.name, attr.value);
|
||||
|
||||
@@ -364,7 +364,7 @@ const DEFAULT_KEYBOARD_ACTIONS = [
|
||||
},
|
||||
{
|
||||
actionName: "findInText",
|
||||
defaultShortcuts: ["CommandOrControl+F"],
|
||||
defaultShortcuts: isElectron ? ["CommandOrControl+F"] : [],
|
||||
scope: "window"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -138,12 +138,6 @@ class Note {
|
||||
return this.hasAttribute('label', 'archived');
|
||||
}
|
||||
|
||||
get isHideInAutocompleteOrArchived() {
|
||||
return this.attributes.find(attr =>
|
||||
attr.type === 'label'
|
||||
&& ["archived", "hideInAutocomplete"].includes(attr.name));
|
||||
}
|
||||
|
||||
get hasInheritableOwnedArchivedLabel() {
|
||||
return !!this.ownedAttributes.find(attr => attr.type === 'label' && attr.name === 'archived' && attr.isInheritable);
|
||||
}
|
||||
@@ -155,20 +149,19 @@ class Note {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {string} - returns flattened textual representation of note, prefixes and attributes usable for searching
|
||||
* This is used for:
|
||||
* - fast searching
|
||||
* - note similarity evaluation
|
||||
*
|
||||
* @return {string} - returns flattened textual representation of note, prefixes and attributes
|
||||
*/
|
||||
get flatText() {
|
||||
if (!this.flatTextCache) {
|
||||
if (this.isHideInAutocompleteOrArchived) {
|
||||
this.flatTextCache = " "; // can't be empty
|
||||
return this.flatTextCache;
|
||||
}
|
||||
|
||||
this.flatTextCache = this.noteId + ' ' + this.type + ' ' + this.mime;
|
||||
this.flatTextCache = this.noteId + ' ' + this.type + ' ' + this.mime + ' ';
|
||||
|
||||
for (const branch of this.parentBranches) {
|
||||
if (branch.prefix) {
|
||||
this.flatTextCache += branch.prefix + ' - ';
|
||||
this.flatTextCache += branch.prefix + ' ';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,11 +169,13 @@ class Note {
|
||||
|
||||
for (const attr of this.attributes) {
|
||||
// it's best to use space as separator since spaces are filtered from the search string by the tokenization into words
|
||||
this.flatTextCache += ' ' + (attr.type === 'label' ? '#' : '@') + attr.name;
|
||||
this.flatTextCache += (attr.type === 'label' ? '#' : '~') + attr.name;
|
||||
|
||||
if (attr.value) {
|
||||
this.flatTextCache += '=' + attr.value;
|
||||
}
|
||||
|
||||
this.flatTextCache += ' ';
|
||||
}
|
||||
|
||||
this.flatTextCache = this.flatTextCache.toLowerCase();
|
||||
@@ -337,6 +332,21 @@ class Note {
|
||||
this.isDecrypted = true;
|
||||
}
|
||||
}
|
||||
|
||||
// for logging etc
|
||||
get pojo() {
|
||||
const pojo = {...this};
|
||||
|
||||
delete pojo.noteCache;
|
||||
delete pojo.ancestorCache;
|
||||
delete pojo.attributeCache;
|
||||
delete pojo.flatTextCache;
|
||||
delete pojo.children;
|
||||
delete pojo.parents;
|
||||
delete pojo.parentBranches;
|
||||
|
||||
return pojo;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Note;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
const noteCache = require('./note_cache');
|
||||
const hoistedNoteService = require('../hoisted_note');
|
||||
const protectedSessionService = require('../protected_session');
|
||||
const stringSimilarity = require('string-similarity');
|
||||
const log = require('../log');
|
||||
|
||||
function isNotePathArchived(notePath) {
|
||||
@@ -174,64 +173,6 @@ function getNotePath(noteId) {
|
||||
}
|
||||
}
|
||||
|
||||
function evaluateSimilarity(sourceNote, candidateNote, results) {
|
||||
let coeff = stringSimilarity.compareTwoStrings(sourceNote.flatText, candidateNote.flatText);
|
||||
|
||||
if (coeff > 0.4) {
|
||||
const notePath = getSomePath(candidateNote);
|
||||
|
||||
// this takes care of note hoisting
|
||||
if (!notePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNotePathArchived(notePath)) {
|
||||
coeff -= 0.2; // archived penalization
|
||||
}
|
||||
|
||||
results.push({coeff, notePath, noteId: candidateNote.noteId});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Point of this is to break up long running sync process to avoid blocking
|
||||
* see https://snyk.io/blog/nodejs-how-even-quick-async-functions-can-block-the-event-loop-starve-io/
|
||||
*/
|
||||
function setImmediatePromise() {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => resolve(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
function findSimilarNotes(noteId) {
|
||||
const results = [];
|
||||
let i = 0;
|
||||
|
||||
const origNote = noteCache.notes[noteId];
|
||||
|
||||
if (!origNote) {
|
||||
return [];
|
||||
}
|
||||
|
||||
for (const note of Object.values(noteCache.notes)) {
|
||||
if (note.isProtected && !note.isDecrypted) {
|
||||
continue;
|
||||
}
|
||||
|
||||
evaluateSimilarity(origNote, note, results);
|
||||
|
||||
i++;
|
||||
|
||||
if (i % 200 === 0) {
|
||||
setImmediatePromise();
|
||||
}
|
||||
}
|
||||
|
||||
results.sort((a, b) => a.coeff > b.coeff ? -1 : 1);
|
||||
|
||||
return results.length > 50 ? results.slice(0, 50) : results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param noteId
|
||||
* @returns {boolean} - true if note exists (is not deleted) and is available in current note hoisting
|
||||
@@ -250,5 +191,5 @@ module.exports = {
|
||||
isAvailable,
|
||||
isArchived,
|
||||
isInAncestor,
|
||||
findSimilarNotes
|
||||
isNotePathArchived
|
||||
};
|
||||
|
||||
@@ -0,0 +1,394 @@
|
||||
const noteCache = require('./note_cache');
|
||||
const noteCacheService = require('./note_cache_service.js');
|
||||
const dateUtils = require('../date_utils');
|
||||
|
||||
const DEBUG = true;
|
||||
|
||||
const IGNORED_ATTRS = [
|
||||
"datenote",
|
||||
"monthnote",
|
||||
"yearnote"
|
||||
];
|
||||
|
||||
const IGNORED_ATTR_NAMES = [
|
||||
"includenotelink",
|
||||
"internallink",
|
||||
"imagelink",
|
||||
"relationmaplink",
|
||||
"template",
|
||||
"disableversioning",
|
||||
"archived",
|
||||
"hidepromotedattributes",
|
||||
"keyboardshortcut",
|
||||
"bookzoomlevel",
|
||||
"noteinfowidgetdisabled",
|
||||
"linkmapwidgetdisabled",
|
||||
"noterevisionswidgetdisabled",
|
||||
"whatlinksherewidgetdisabled",
|
||||
"similarnoteswidgetdisabled",
|
||||
"disableinclusion",
|
||||
"rendernote",
|
||||
"pageurl",
|
||||
];
|
||||
|
||||
function filterUrlValue(value) {
|
||||
return value
|
||||
.replace(/https?:\/\//ig, "")
|
||||
.replace(/www\./ig, "")
|
||||
.replace(/(\.net|\.com|\.org|\.info|\.edu)/ig, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Note} note
|
||||
*/
|
||||
function buildRewardMap(note) {
|
||||
const map = {};
|
||||
|
||||
function addToRewardMap(text, rewardFactor) {
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const word of splitToWords(text)) {
|
||||
if (word) {
|
||||
map[word] = map[word] || 0;
|
||||
|
||||
// reward grows with the length of matched string
|
||||
const length = word.length
|
||||
- 0.9; // to penalize specifically very short words - 1 and 2 characters
|
||||
|
||||
map[word] += rewardFactor * Math.pow(length, 0.7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const ancestorNote of note.ancestors) {
|
||||
if (ancestorNote.noteId === 'root') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ancestorNote.isDecrypted) {
|
||||
addToRewardMap(ancestorNote.title, 0.3);
|
||||
}
|
||||
|
||||
for (const branch of ancestorNote.parentBranches) {
|
||||
addToRewardMap(branch.prefix, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
addToRewardMap(trimMime(note.mime), 0.5);
|
||||
|
||||
if (note.isDecrypted) {
|
||||
addToRewardMap(note.title, 1);
|
||||
}
|
||||
|
||||
for (const branch of note.parentBranches) {
|
||||
addToRewardMap(branch.prefix, 1);
|
||||
}
|
||||
|
||||
for (const attr of note.attributes) {
|
||||
if (attr.name.startsWith('child:')
|
||||
|| attr.name.startsWith('relation:')
|
||||
|| attr.name.startsWith('label:')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// inherited notes get small penalization
|
||||
let reward = note.noteId === attr.noteId ? 0.8 : 0.5;
|
||||
|
||||
if (IGNORED_ATTRS.includes(attr.name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IGNORED_ATTR_NAMES.includes(attr.name)) {
|
||||
addToRewardMap(attr.name, reward);
|
||||
}
|
||||
|
||||
let value = attr.value;
|
||||
|
||||
if (value.startsWith('http')) {
|
||||
value = filterUrlValue(value);
|
||||
|
||||
// words in URLs are not that valuable
|
||||
reward = reward / 2;
|
||||
}
|
||||
|
||||
addToRewardMap(value, reward);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
const mimeCache = {};
|
||||
|
||||
function trimMime(mime) {
|
||||
if (!mime || mime === 'text/html') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(mime in mimeCache)) {
|
||||
const chunks = mime.split('/');
|
||||
|
||||
let str = "";
|
||||
|
||||
if (chunks.length >= 2) {
|
||||
// we're not interested in 'text/' or 'application/' prefix
|
||||
str = chunks[1];
|
||||
|
||||
if (str.startsWith('-x')) {
|
||||
str = str.substr(2);
|
||||
}
|
||||
}
|
||||
|
||||
mimeCache[mime] = str;
|
||||
mimeCache[mime] = str;
|
||||
}
|
||||
|
||||
return mimeCache[mime];
|
||||
}
|
||||
|
||||
function buildDateLimits(baseNote) {
|
||||
const dateCreatedTs = dateUtils.parseDateTime(baseNote.utcDateCreated);
|
||||
|
||||
return {
|
||||
minDate: dateUtils.utcDateStr(new Date(dateCreatedTs - 3600)),
|
||||
minExcludedDate: dateUtils.utcDateStr(new Date(dateCreatedTs - 5)),
|
||||
maxExcludedDate: dateUtils.utcDateStr(new Date(dateCreatedTs + 5)),
|
||||
maxDate: dateUtils.utcDateStr(new Date(dateCreatedTs + 3600)),
|
||||
};
|
||||
}
|
||||
|
||||
const wordCache = {};
|
||||
|
||||
const WORD_BLACKLIST = [
|
||||
"a", "the", "in", "for", "from", "but", "s", "so", "if", "while", "until",
|
||||
"whether", "after", "before", "because", "since", "when", "where", "how",
|
||||
"than", "then", "and", "either", "or", "neither", "nor", "both", "also"
|
||||
];
|
||||
|
||||
function splitToWords(text) {
|
||||
let words = wordCache[text];
|
||||
|
||||
if (!words) {
|
||||
wordCache[text] = words = text.toLowerCase().split(/[^\p{L}\p{N}]+/u);
|
||||
|
||||
for (const idx in words) {
|
||||
if (WORD_BLACKLIST.includes(words[idx])) {
|
||||
words[idx] = "";
|
||||
}
|
||||
// special case for english plurals
|
||||
else if (words[idx].length > 2 && words[idx].endsWith("es")) {
|
||||
words[idx] = words[idx].substr(0, words[idx] - 2);
|
||||
}
|
||||
else if (words[idx].length > 1 && words[idx].endsWith("s")) {
|
||||
words[idx] = words[idx].substr(0, words[idx] - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
/**
|
||||
* includeNoteLink and imageLink relation mean that notes are clearly related, but so clearly
|
||||
* that it doesn't actually need to be shown to the user.
|
||||
*/
|
||||
function hasConnectingRelation(sourceNote, targetNote) {
|
||||
return sourceNote.attributes.find(attr => attr.type === 'relation'
|
||||
&& ['includenotelink', 'imagelink'].includes(attr.name)
|
||||
&& attr.value === targetNote.noteId);
|
||||
}
|
||||
|
||||
async function findSimilarNotes(noteId) {
|
||||
const results = [];
|
||||
let i = 0;
|
||||
|
||||
const baseNote = noteCache.notes[noteId];
|
||||
|
||||
if (!baseNote) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const dateLimits = buildDateLimits(baseNote);
|
||||
const rewardMap = buildRewardMap(baseNote);
|
||||
const ancestorRewardCache = {};
|
||||
const ancestorNoteIds = new Set(baseNote.ancestors.map(note => note.noteId));
|
||||
let displayRewards = false;
|
||||
|
||||
function gatherRewards(text, factor = 1) {
|
||||
if (!text) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let counter = 0;
|
||||
|
||||
// when the title is very long then weight of each individual word should be lower
|
||||
// also pretty important in e.g. long URLs in label values
|
||||
const lengthPenalization = 1 / Math.pow(text.length, 0.3);
|
||||
|
||||
for (const word of splitToWords(text)) {
|
||||
const reward = rewardMap[word] * factor * lengthPenalization || 0;
|
||||
|
||||
if (displayRewards && reward > 0) {
|
||||
console.log(`Reward ${Math.round(reward * 10) / 10} for word: ${word}`);
|
||||
}
|
||||
|
||||
counter += reward;
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
function gatherAncestorRewards(note) {
|
||||
if (!(note.noteId in ancestorRewardCache)) {
|
||||
let score = 0;
|
||||
|
||||
for (const parentNote of note.parents) {
|
||||
if (!ancestorNoteIds.has(parentNote.noteId)) {
|
||||
if (parentNote.isDecrypted) {
|
||||
score += gatherRewards(parentNote.title, 0.3);
|
||||
}
|
||||
|
||||
for (const branch of parentNote.parentBranches) {
|
||||
score += gatherRewards(branch.prefix, 0.3)
|
||||
+ gatherAncestorRewards(branch.parentNote);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ancestorRewardCache[note.noteId] = score;
|
||||
}
|
||||
|
||||
return ancestorRewardCache[note.noteId];
|
||||
}
|
||||
|
||||
function computeScore(candidateNote) {
|
||||
let score = gatherRewards(trimMime(candidateNote.mime))
|
||||
+ gatherAncestorRewards(candidateNote);
|
||||
|
||||
if (candidateNote.isDecrypted) {
|
||||
score += gatherRewards(candidateNote.title);
|
||||
}
|
||||
|
||||
for (const branch of candidateNote.parentBranches) {
|
||||
score += gatherRewards(branch.prefix);
|
||||
}
|
||||
|
||||
for (const attr of candidateNote.attributes) {
|
||||
if (attr.name.startsWith('child:')
|
||||
|| attr.name.startsWith('relation:')
|
||||
|| attr.name.startsWith('label:')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IGNORED_ATTRS.includes(attr.name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IGNORED_ATTR_NAMES.includes(attr.name)) {
|
||||
score += gatherRewards(attr.name);
|
||||
}
|
||||
|
||||
let value = attr.value;
|
||||
let factor = 1;
|
||||
|
||||
if (value.startsWith('http')) {
|
||||
value = filterUrlValue(value);
|
||||
|
||||
// words in URLs are not that valuable
|
||||
factor = 0.5;
|
||||
}
|
||||
|
||||
score += gatherRewards(attr.value, factor);
|
||||
}
|
||||
|
||||
if (candidateNote.type === baseNote.type) {
|
||||
score += 0.2;
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to improve standing of notes which have been created in similar time to each other since
|
||||
* there's a good chance they are related.
|
||||
*
|
||||
* But there's an exception - if they were created really close to each other (withing few seconds) then
|
||||
* they are probably part of the import and not created by hand - these OTOH should not benefit.
|
||||
*/
|
||||
const {utcDateCreated} = candidateNote;
|
||||
|
||||
if (utcDateCreated < dateLimits.minExcludedDate && utcDateCreated > dateLimits.maxExcludedDate) {
|
||||
if (utcDateCreated >= dateLimits.minDate && utcDateCreated <= dateLimits.maxDate) {
|
||||
score += 1;
|
||||
}
|
||||
else if (utcDateCreated.substr(0, 10) === dateLimits.minDate.substr(0, 10) || utcDateCreated.substr(0, 10) === dateLimits.maxDate.substr(0, 10)) {
|
||||
// smaller bonus when outside of the window but within same date
|
||||
score += 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
for (const candidateNote of Object.values(noteCache.notes)) {
|
||||
if (candidateNote.noteId === baseNote.noteId
|
||||
|| hasConnectingRelation(candidateNote, baseNote)
|
||||
|| hasConnectingRelation(baseNote, candidateNote)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let score = computeScore(candidateNote);
|
||||
|
||||
if (score >= 2) {
|
||||
const notePath = noteCacheService.getSomePath(candidateNote);
|
||||
|
||||
// this takes care of note hoisting
|
||||
if (!notePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (noteCacheService.isNotePathArchived(notePath)) {
|
||||
score -= 0.5; // archived penalization
|
||||
}
|
||||
|
||||
results.push({score, notePath, noteId: candidateNote.noteId});
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if (i % 1000 === 0) {
|
||||
await setImmediatePromise();
|
||||
}
|
||||
}
|
||||
|
||||
results.sort((a, b) => a.score > b.score ? -1 : 1);
|
||||
|
||||
if (DEBUG) {
|
||||
console.log("REWARD MAP", rewardMap);
|
||||
|
||||
if (results.length >= 1) {
|
||||
const note = noteCache.notes[results[0].noteId];
|
||||
|
||||
console.log("WINNER", note.pojo);
|
||||
|
||||
displayRewards = true;
|
||||
const totalReward = computeScore(note);
|
||||
|
||||
console.log("Total reward:", Math.round(totalReward * 10) / 10);
|
||||
}
|
||||
}
|
||||
|
||||
return results.length > 200 ? results.slice(0, 200) : results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Point of this is to break up long running sync process to avoid blocking
|
||||
* see https://snyk.io/blog/nodejs-how-even-quick-async-functions-can-block-the-event-loop-starve-io/
|
||||
*/
|
||||
function setImmediatePromise() {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => resolve(), 0);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
findSimilarNotes
|
||||
};
|
||||
@@ -30,6 +30,14 @@ function createNoteRevision(note) {
|
||||
return;
|
||||
}
|
||||
|
||||
const content = note.getContent();
|
||||
|
||||
if (!content) {
|
||||
return;
|
||||
}
|
||||
|
||||
const contentMetadata = note.getContentMetadata();
|
||||
|
||||
const noteRevision = new NoteRevision({
|
||||
noteId: note.noteId,
|
||||
// title and text should be decrypted now
|
||||
@@ -37,14 +45,18 @@ function createNoteRevision(note) {
|
||||
type: note.type,
|
||||
mime: note.mime,
|
||||
isProtected: false, // will be fixed in the protectNoteRevisions() call
|
||||
utcDateLastEdited: note.utcDateModified,
|
||||
utcDateLastEdited: note.utcDateModified > contentMetadata.utcDateModified
|
||||
? note.utcDateModified
|
||||
: contentMetadata.utcDateModified,
|
||||
utcDateCreated: dateUtils.utcNowDateTime(),
|
||||
utcDateModified: dateUtils.utcNowDateTime(),
|
||||
dateLastEdited: note.dateModified,
|
||||
dateLastEdited: note.dateModified > contentMetadata.dateModified
|
||||
? note.dateModified
|
||||
: contentMetadata.dateModified,
|
||||
dateCreated: dateUtils.localNowDateTime()
|
||||
}).save();
|
||||
|
||||
noteRevision.setContent(note.getContent());
|
||||
noteRevision.setContent(content);
|
||||
|
||||
return noteRevision;
|
||||
}
|
||||
|
||||
+4
-16
@@ -55,13 +55,15 @@ function deriveMime(type, mime) {
|
||||
mime = 'application/json';
|
||||
} else if (['render', 'book'].includes(type)) {
|
||||
mime = '';
|
||||
} else {
|
||||
mime = 'application/octet-stream';
|
||||
}
|
||||
|
||||
return mime;
|
||||
}
|
||||
|
||||
function copyChildAttributes(parentNote, childNote) {
|
||||
for (const attr of parentNote.getOwnedAttributes()) {
|
||||
for (const attr of parentNote.getAttributes()) {
|
||||
if (attr.name.startsWith("child:")) {
|
||||
new Attribute({
|
||||
noteId: childNote.noteId,
|
||||
@@ -464,21 +466,7 @@ function saveNoteRevision(note) {
|
||||
const msSinceDateCreated = now.getTime() - dateUtils.parseDateTime(note.utcDateCreated).getTime();
|
||||
|
||||
if (!existingNoteRevisionId && msSinceDateCreated >= noteRevisionSnapshotTimeInterval * 1000) {
|
||||
const noteRevision = new NoteRevision({
|
||||
noteId: note.noteId,
|
||||
// title and text should be decrypted now
|
||||
title: note.title,
|
||||
type: note.type,
|
||||
mime: note.mime,
|
||||
isProtected: false, // will be fixed in the protectNoteRevisions() call
|
||||
utcDateLastEdited: note.utcDateModified,
|
||||
utcDateCreated: dateUtils.utcNowDateTime(),
|
||||
utcDateModified: dateUtils.utcNowDateTime(),
|
||||
dateLastEdited: note.dateModified,
|
||||
dateCreated: dateUtils.localNowDateTime()
|
||||
}).save();
|
||||
|
||||
noteRevision.setContent(note.getContent());
|
||||
noteRevisionService.createNoteRevision(note);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,9 @@ const defaultOptions = [
|
||||
{ name: 'hideArchivedNotes_main', value: 'false', isSynced: false },
|
||||
{ name: 'hideIncludedImages_main', value: 'true', isSynced: false },
|
||||
{ name: 'attributeListExpanded', value: 'false', isSynced: false },
|
||||
{ name: 'promotedAttributesExpanded', value: 'false', isSynced: true }
|
||||
{ name: 'promotedAttributesExpanded', value: 'true', isSynced: true },
|
||||
{ name: 'similarNotesExpanded', value: 'true', isSynced: true },
|
||||
{ name: 'debugModeEnabled', value: 'false', isSynced: false }
|
||||
];
|
||||
|
||||
function initStartupOptions() {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
function parse(value) {
|
||||
const tokens = value.split(',').map(t => t.trim());
|
||||
const defObj = {};
|
||||
|
||||
for (const token of tokens) {
|
||||
if (token === 'promoted') {
|
||||
defObj.isPromoted = true;
|
||||
}
|
||||
else if (['text', 'number', 'boolean', 'date', 'url'].includes(token)) {
|
||||
defObj.labelType = token;
|
||||
}
|
||||
else if (['single', 'multi'].includes(token)) {
|
||||
defObj.multiplicity = token;
|
||||
}
|
||||
else if (token.startsWith('precision')) {
|
||||
const chunks = token.split('=');
|
||||
|
||||
defObj.numberPrecision = parseInt(chunks[1]);
|
||||
}
|
||||
else if (token.startsWith('inverse')) {
|
||||
const chunks = token.split('=');
|
||||
|
||||
defObj.inverseRelation = chunks[1];
|
||||
}
|
||||
else {
|
||||
console.log("Unrecognized attribute definition token:", token);
|
||||
}
|
||||
}
|
||||
|
||||
return defObj;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
parse
|
||||
};
|
||||
@@ -1,8 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
class ParsingContext {
|
||||
class SearchContext {
|
||||
constructor(params = {}) {
|
||||
this.includeNoteContent = !!params.includeNoteContent;
|
||||
this.excludeArchived = !!params.excludeArchived;
|
||||
this.fuzzyAttributeSearch = !!params.fuzzyAttributeSearch;
|
||||
this.highlightedTokens = [];
|
||||
this.originalQuery = "";
|
||||
@@ -17,4 +18,4 @@ class ParsingContext {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ParsingContext;
|
||||
module.exports = SearchContext;
|
||||
@@ -18,39 +18,32 @@ const OrderByAndLimitExp = require('../expressions/order_by_and_limit.js');
|
||||
const buildComparator = require('./build_comparator.js');
|
||||
const ValueExtractor = require('../value_extractor.js');
|
||||
|
||||
function getFulltext(tokens, parsingContext) {
|
||||
function getFulltext(tokens, searchContext) {
|
||||
tokens = tokens.map(t => t.token);
|
||||
|
||||
parsingContext.highlightedTokens.push(...tokens);
|
||||
searchContext.highlightedTokens.push(...tokens);
|
||||
|
||||
if (tokens.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let textSearchExpression;
|
||||
|
||||
if (parsingContext.includeNoteContent) {
|
||||
textSearchExpression = new OrExp([
|
||||
if (searchContext.includeNoteContent) {
|
||||
return new OrExp([
|
||||
new NoteCacheFulltextExp(tokens),
|
||||
new NoteContentProtectedFulltextExp('*=*', tokens),
|
||||
new NoteContentUnprotectedFulltextExp('*=*', tokens)
|
||||
]);
|
||||
}
|
||||
else {
|
||||
textSearchExpression = new NoteCacheFulltextExp(tokens);
|
||||
return new NoteCacheFulltextExp(tokens);
|
||||
}
|
||||
|
||||
return new AndExp([
|
||||
textSearchExpression,
|
||||
new PropertyComparisonExp("isarchived", buildComparator("=", "false"))
|
||||
]);
|
||||
}
|
||||
|
||||
function isOperator(str) {
|
||||
return str.match(/^[=<>*]+$/);
|
||||
}
|
||||
|
||||
function getExpression(tokens, parsingContext, level = 0) {
|
||||
function getExpression(tokens, searchContext, level = 0) {
|
||||
if (tokens.length === 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -63,11 +56,11 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
function context(i) {
|
||||
let {startIndex, endIndex} = tokens[i];
|
||||
startIndex = Math.max(0, startIndex - 20);
|
||||
endIndex = Math.min(parsingContext.originalQuery.length, endIndex + 20);
|
||||
endIndex = Math.min(searchContext.originalQuery.length, endIndex + 20);
|
||||
|
||||
return '"' + (startIndex !== 0 ? "..." : "")
|
||||
+ parsingContext.originalQuery.substr(startIndex, endIndex - startIndex)
|
||||
+ (endIndex !== parsingContext.originalQuery.length ? "..." : "") + '"';
|
||||
+ searchContext.originalQuery.substr(startIndex, endIndex - startIndex)
|
||||
+ (endIndex !== searchContext.originalQuery.length ? "..." : "") + '"';
|
||||
}
|
||||
|
||||
function resolveConstantOperand() {
|
||||
@@ -75,7 +68,7 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
|
||||
if (!operand.inQuotes
|
||||
&& (operand.token.startsWith('#') || operand.token.startsWith('~') || operand.token === 'note')) {
|
||||
parsingContext.addError(`Error near token "${operand.token}" in ${context(i)}, it's possible to compare with constant only.`);
|
||||
searchContext.addError(`Error near token "${operand.token}" in ${context(i)}, it's possible to compare with constant only.`);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -121,7 +114,7 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
|
||||
function parseNoteProperty() {
|
||||
if (tokens[i].token !== '.') {
|
||||
parsingContext.addError('Expected "." to separate field path');
|
||||
searchContext.addError('Expected "." to separate field path');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -133,7 +126,7 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
const operator = tokens[i].token;
|
||||
|
||||
if (!isOperator(operator)) {
|
||||
parsingContext.addError(`After content expected operator, but got "${tokens[i].token}" in ${context(i)}`);
|
||||
searchContext.addError(`After content expected operator, but got "${tokens[i].token}" in ${context(i)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -165,7 +158,7 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
|
||||
if (tokens[i].token === 'labels') {
|
||||
if (tokens[i + 1].token !== '.') {
|
||||
parsingContext.addError(`Expected "." to separate field path, got "${tokens[i + 1].token}" in ${context(i)}`);
|
||||
searchContext.addError(`Expected "." to separate field path, got "${tokens[i + 1].token}" in ${context(i)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -176,7 +169,7 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
|
||||
if (tokens[i].token === 'relations') {
|
||||
if (tokens[i + 1].token !== '.') {
|
||||
parsingContext.addError(`Expected "." to separate field path, got "${tokens[i + 1].token}" in ${context(i)}`);
|
||||
searchContext.addError(`Expected "." to separate field path, got "${tokens[i + 1].token}" in ${context(i)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -187,13 +180,13 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
|
||||
if (tokens[i].token === 'text') {
|
||||
if (tokens[i + 1].token !== '*=*') {
|
||||
parsingContext.addError(`Virtual attribute "note.text" supports only *=* operator, instead given "${tokens[i + 1].token}" in ${context(i)}`);
|
||||
searchContext.addError(`Virtual attribute "note.text" supports only *=* operator, instead given "${tokens[i + 1].token}" in ${context(i)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
i += 2;
|
||||
|
||||
return getFulltext([tokens[i]], parsingContext);
|
||||
return getFulltext([tokens[i]], searchContext);
|
||||
}
|
||||
|
||||
if (PropertyComparisonExp.isProperty(tokens[i].token)) {
|
||||
@@ -203,7 +196,7 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
const comparator = buildComparator(operator, comparedValue);
|
||||
|
||||
if (!comparator) {
|
||||
parsingContext.addError(`Can't find operator '${operator}' in ${context(i)}`);
|
||||
searchContext.addError(`Can't find operator '${operator}' in ${context(i)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -212,7 +205,7 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
return new PropertyComparisonExp(propertyName, comparator);
|
||||
}
|
||||
|
||||
parsingContext.addError(`Unrecognized note property "${tokens[i].token}" in ${context(i)}`);
|
||||
searchContext.addError(`Unrecognized note property "${tokens[i].token}" in ${context(i)}`);
|
||||
}
|
||||
|
||||
function parseAttribute(name) {
|
||||
@@ -232,7 +225,7 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
}
|
||||
|
||||
function parseLabel(labelName) {
|
||||
parsingContext.highlightedTokens.push(labelName);
|
||||
searchContext.highlightedTokens.push(labelName);
|
||||
|
||||
if (i < tokens.length - 2 && isOperator(tokens[i + 1].token)) {
|
||||
let operator = tokens[i + 1].token;
|
||||
@@ -245,33 +238,33 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
parsingContext.highlightedTokens.push(comparedValue);
|
||||
searchContext.highlightedTokens.push(comparedValue);
|
||||
|
||||
if (parsingContext.fuzzyAttributeSearch && operator === '=') {
|
||||
if (searchContext.fuzzyAttributeSearch && operator === '=') {
|
||||
operator = '*=*';
|
||||
}
|
||||
|
||||
const comparator = buildComparator(operator, comparedValue);
|
||||
|
||||
if (!comparator) {
|
||||
parsingContext.addError(`Can't find operator '${operator}' in ${context(i - 1)}`);
|
||||
searchContext.addError(`Can't find operator '${operator}' in ${context(i - 1)}`);
|
||||
} else {
|
||||
return new LabelComparisonExp('label', labelName, comparator);
|
||||
}
|
||||
} else {
|
||||
return new AttributeExistsExp('label', labelName, parsingContext.fuzzyAttributeSearch);
|
||||
return new AttributeExistsExp('label', labelName, searchContext.fuzzyAttributeSearch);
|
||||
}
|
||||
}
|
||||
|
||||
function parseRelation(relationName) {
|
||||
parsingContext.highlightedTokens.push(relationName);
|
||||
searchContext.highlightedTokens.push(relationName);
|
||||
|
||||
if (i < tokens.length - 2 && tokens[i + 1].token === '.') {
|
||||
i += 1;
|
||||
|
||||
return new RelationWhereExp(relationName, parseNoteProperty());
|
||||
} else {
|
||||
return new AttributeExistsExp('relation', relationName, parsingContext.fuzzyAttributeSearch);
|
||||
return new AttributeExistsExp('relation', relationName, searchContext.fuzzyAttributeSearch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +293,7 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
const valueExtractor = new ValueExtractor(propertyPath);
|
||||
|
||||
if (valueExtractor.validate()) {
|
||||
parsingContext.addError(valueExtractor.validate());
|
||||
searchContext.addError(valueExtractor.validate());
|
||||
}
|
||||
|
||||
orderDefinitions.push({
|
||||
@@ -328,7 +321,7 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
|
||||
for (i = 0; i < tokens.length; i++) {
|
||||
if (Array.isArray(tokens[i])) {
|
||||
expressions.push(getExpression(tokens[i], parsingContext, level++));
|
||||
expressions.push(getExpression(tokens[i], searchContext, level++));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -343,7 +336,7 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
}
|
||||
else if (['orderby', 'limit'].includes(token)) {
|
||||
if (level !== 0) {
|
||||
parsingContext.addError('orderBy can appear only on the top expression level');
|
||||
searchContext.addError('orderBy can appear only on the top expression level');
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -361,11 +354,11 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
i += 1;
|
||||
|
||||
if (!Array.isArray(tokens[i])) {
|
||||
parsingContext.addError(`not keyword should be followed by sub-expression in parenthesis, got ${tokens[i].token} instead`);
|
||||
searchContext.addError(`not keyword should be followed by sub-expression in parenthesis, got ${tokens[i].token} instead`);
|
||||
continue;
|
||||
}
|
||||
|
||||
expressions.push(new NotExp(getExpression(tokens[i], parsingContext, level++)));
|
||||
expressions.push(new NotExp(getExpression(tokens[i], searchContext, level++)));
|
||||
}
|
||||
else if (token === 'note') {
|
||||
i++;
|
||||
@@ -379,14 +372,14 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
op = token;
|
||||
}
|
||||
else if (op !== token) {
|
||||
parsingContext.addError('Mixed usage of AND/OR - always use parenthesis to group AND/OR expressions.');
|
||||
searchContext.addError('Mixed usage of AND/OR - always use parenthesis to group AND/OR expressions.');
|
||||
}
|
||||
}
|
||||
else if (isOperator(token)) {
|
||||
parsingContext.addError(`Misplaced or incomplete expression "${token}"`);
|
||||
searchContext.addError(`Misplaced or incomplete expression "${token}"`);
|
||||
}
|
||||
else {
|
||||
parsingContext.addError(`Unrecognized expression "${token}"`);
|
||||
searchContext.addError(`Unrecognized expression "${token}"`);
|
||||
}
|
||||
|
||||
if (!op && expressions.length > 1) {
|
||||
@@ -397,10 +390,11 @@ function getExpression(tokens, parsingContext, level = 0) {
|
||||
return getAggregateExpression();
|
||||
}
|
||||
|
||||
function parse({fulltextTokens, expressionTokens, parsingContext}) {
|
||||
function parse({fulltextTokens, expressionTokens, searchContext}) {
|
||||
return AndExp.of([
|
||||
getFulltext(fulltextTokens, parsingContext),
|
||||
getExpression(expressionTokens, parsingContext)
|
||||
searchContext.excludeArchived ? new PropertyComparisonExp("isarchived", buildComparator("=", "false")) : null,
|
||||
getFulltext(fulltextTokens, searchContext),
|
||||
getExpression(expressionTokens, searchContext)
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ const handleParens = require('./handle_parens.js');
|
||||
const parse = require('./parse.js');
|
||||
const NoteSet = require("../note_set.js");
|
||||
const SearchResult = require("../search_result.js");
|
||||
const ParsingContext = require("../parsing_context.js");
|
||||
const SearchContext = require("../search_context.js");
|
||||
const noteCache = require('../../note_cache/note_cache.js');
|
||||
const noteCacheService = require('../../note_cache/note_cache_service.js');
|
||||
const hoistedNoteService = require('../../hoisted_note.js');
|
||||
@@ -50,14 +50,14 @@ function findNotesWithExpression(expression) {
|
||||
return searchResults;
|
||||
}
|
||||
|
||||
function parseQueryToExpression(query, parsingContext) {
|
||||
function parseQueryToExpression(query, searchContext) {
|
||||
const {fulltextTokens, expressionTokens} = lex(query);
|
||||
const structuredExpressionTokens = handleParens(expressionTokens);
|
||||
|
||||
const expression = parse({
|
||||
fulltextTokens,
|
||||
expressionTokens: structuredExpressionTokens,
|
||||
parsingContext,
|
||||
searchContext,
|
||||
originalQuery: query
|
||||
});
|
||||
|
||||
@@ -66,12 +66,16 @@ function parseQueryToExpression(query, parsingContext) {
|
||||
|
||||
/**
|
||||
* @param {string} query
|
||||
* @param {ParsingContext} parsingContext
|
||||
* @param {SearchContext} searchContext
|
||||
* @return {SearchResult[]}
|
||||
*/
|
||||
function findNotesWithQuery(query, parsingContext) {
|
||||
function findNotesWithQuery(query, searchContext) {
|
||||
if (!query.trim().length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return utils.stopWatch(`Search with query "${query}"`, () => {
|
||||
const expression = parseQueryToExpression(query, parsingContext);
|
||||
const expression = parseQueryToExpression(query, searchContext);
|
||||
|
||||
if (!expression) {
|
||||
return [];
|
||||
@@ -81,24 +85,8 @@ function findNotesWithQuery(query, parsingContext) {
|
||||
}, 20);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {SearchResult[]}
|
||||
*/
|
||||
function searchNotes(query) {
|
||||
if (!query.trim().length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const parsingContext = new ParsingContext({
|
||||
includeNoteContent: true,
|
||||
fuzzyAttributeSearch: false
|
||||
});
|
||||
|
||||
return findNotesWithQuery(query, parsingContext);
|
||||
}
|
||||
|
||||
function searchTrimmedNotes(query) {
|
||||
const allSearchResults = searchNotes(query);
|
||||
function searchTrimmedNotes(query, searchContext) {
|
||||
const allSearchResults = findNotesWithQuery(query, searchContext);
|
||||
const trimmedSearchResults = allSearchResults.slice(0, 200);
|
||||
|
||||
return {
|
||||
@@ -108,22 +96,17 @@ function searchTrimmedNotes(query) {
|
||||
}
|
||||
|
||||
function searchNotesForAutocomplete(query) {
|
||||
if (!query.trim().length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const parsingContext = new ParsingContext({
|
||||
const searchContext = new SearchContext({
|
||||
includeNoteContent: false,
|
||||
excludeArchived: true,
|
||||
fuzzyAttributeSearch: true
|
||||
});
|
||||
|
||||
let searchResults = findNotesWithQuery(query, parsingContext);
|
||||
const {results} = searchTrimmedNotes(query, searchContext);
|
||||
|
||||
searchResults = searchResults.slice(0, 200);
|
||||
highlightSearchResults(results, searchContext.highlightedTokens);
|
||||
|
||||
highlightSearchResults(searchResults, parsingContext.highlightedTokens);
|
||||
|
||||
return searchResults.map(result => {
|
||||
return results.map(result => {
|
||||
return {
|
||||
notePath: result.notePath,
|
||||
noteTitle: noteCacheService.getNoteTitle(result.noteId),
|
||||
@@ -196,15 +179,8 @@ function formatAttribute(attr) {
|
||||
}
|
||||
}
|
||||
|
||||
function searchNoteEntities(query) {
|
||||
return searchNotes(query)
|
||||
.map(res => repository.getNote(res.noteId));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
searchNotes,
|
||||
searchTrimmedNotes,
|
||||
searchNotesForAutocomplete,
|
||||
findNotesWithQuery,
|
||||
searchNoteEntities
|
||||
findNotesWithQuery
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ function isDbInitialized() {
|
||||
|
||||
async function initDbConnection() {
|
||||
if (!isDbInitialized()) {
|
||||
log.info(`DB not initialized, please visit setup page` + (utils.isElectron() ? '' : ` - http://[your-server-host]:${port} to see instructions on how to initialize Trilium.`));
|
||||
log.info(`DB not initialized, please visit setup page` + (utils.isElectron() ? '' : ` - http://[your-server-host]:${await port} to see instructions on how to initialize Trilium.`));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -101,6 +101,8 @@
|
||||
|
||||
<div class="dropdown-menu dropdown-menu-sm" id="context-menu-container"></div>
|
||||
|
||||
<%- include('dialogs/confirm.ejs') %>
|
||||
|
||||
<script type="text/javascript">
|
||||
window.baseApiUrl = 'api/';
|
||||
window.device = "mobile";
|
||||
|
||||
@@ -14,7 +14,6 @@ process.on('SIGINT', function() {
|
||||
});
|
||||
|
||||
const { app, sessionParser } = require('./app');
|
||||
const debug = require('debug')('node:server');
|
||||
const fs = require('fs');
|
||||
const http = require('http');
|
||||
const https = require('https');
|
||||
@@ -100,7 +99,7 @@ async function startTrilium() {
|
||||
}
|
||||
)
|
||||
|
||||
httpServer.on('listening', () => debug('Listening on port' + httpServer.address().port));
|
||||
httpServer.on('listening', () => log.info('Listening on port' + httpServer.address().port));
|
||||
|
||||
ws.init(httpServer, sessionParser);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user