mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
many small issues found by intellij analysis
This commit is contained in:
parent
be654e7a31
commit
f50a9c250a
1
package-lock.json
generated
1
package-lock.json
generated
@ -71,6 +71,7 @@
|
|||||||
"turndown": "7.1.1",
|
"turndown": "7.1.1",
|
||||||
"unescape": "1.0.1",
|
"unescape": "1.0.1",
|
||||||
"ws": "8.12.0",
|
"ws": "8.12.0",
|
||||||
|
"xml2js": "^0.4.23",
|
||||||
"yauzl": "2.10.0"
|
"yauzl": "2.10.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -88,6 +88,7 @@
|
|||||||
"turndown": "7.1.1",
|
"turndown": "7.1.1",
|
||||||
"unescape": "1.0.1",
|
"unescape": "1.0.1",
|
||||||
"ws": "8.12.0",
|
"ws": "8.12.0",
|
||||||
|
"xml2js": "0.4.23",
|
||||||
"yauzl": "2.10.0"
|
"yauzl": "2.10.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
const backupService = require('./services/backup');
|
const anonymizationService = require('./services/anonymization');
|
||||||
const sqlInit = require('./services/sql_init');
|
const sqlInit = require('./services/sql_init');
|
||||||
require('./entities/entity_constructor');
|
require('./becca/entity_constructor');
|
||||||
|
|
||||||
sqlInit.dbReady.then(async () => {
|
sqlInit.dbReady.then(async () => {
|
||||||
try {
|
try {
|
||||||
console.log("Starting anonymization...");
|
console.log("Starting anonymization...");
|
||||||
|
|
||||||
const resp = await backupService.anonymize();
|
const resp = await anonymizationService.createAnonymizedCopy('full');
|
||||||
|
|
||||||
if (resp.success) {
|
if (resp.success) {
|
||||||
console.log(`Anonymized file has been saved to: ${resp.anonymizedFilePath}`);
|
console.log(`Anonymized file has been saved to: ${resp.anonymizedFilePath}`);
|
||||||
|
@ -121,17 +121,17 @@ class Becca {
|
|||||||
return row ? new BNoteRevision(row) : null;
|
return row ? new BNoteRevision(row) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {Option|null} */
|
/** @returns {BOption|null} */
|
||||||
getOption(name) {
|
getOption(name) {
|
||||||
return this.options[name];
|
return this.options[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {EtapiToken[]} */
|
/** @returns {BEtapiToken[]} */
|
||||||
getEtapiTokens() {
|
getEtapiTokens() {
|
||||||
return Object.values(this.etapiTokens);
|
return Object.values(this.etapiTokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {EtapiToken|null} */
|
/** @returns {BEtapiToken|null} */
|
||||||
getEtapiToken(etapiTokenId) {
|
getEtapiToken(etapiTokenId) {
|
||||||
return this.etapiTokens[etapiTokenId];
|
return this.etapiTokens[etapiTokenId];
|
||||||
}
|
}
|
||||||
@ -168,7 +168,7 @@ class Becca {
|
|||||||
const rows = sql.getRows(query, params);
|
const rows = sql.getRows(query, params);
|
||||||
|
|
||||||
const BNoteRevision = require("./entities/bnote_revision"); // avoiding circular dependency problems
|
const BNoteRevision = require("./entities/bnote_revision"); // avoiding circular dependency problems
|
||||||
return rows.map(row => new NoteRevision(row));
|
return rows.map(row => new BNoteRevision(row));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Should be called when the set of all non-skeleton notes changes (added/removed) */
|
/** Should be called when the set of all non-skeleton notes changes (added/removed) */
|
||||||
|
@ -53,7 +53,7 @@ class BBranch extends AbstractBeccaEntity {
|
|||||||
this.noteId = noteId;
|
this.noteId = noteId;
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
this.parentNoteId = parentNoteId;
|
this.parentNoteId = parentNoteId;
|
||||||
/** @type {string} */
|
/** @type {string|null} */
|
||||||
this.prefix = prefix;
|
this.prefix = prefix;
|
||||||
/** @type {int} */
|
/** @type {int} */
|
||||||
this.notePosition = notePosition;
|
this.notePosition = notePosition;
|
||||||
|
@ -195,9 +195,9 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Note content has quite special handling - it's not a separate entity, but a lazily loaded
|
* Note content has quite special handling - it's not a separate entity, but a lazily loaded
|
||||||
* part of Note entity with it's own sync. Reasons behind this hybrid design has been:
|
* part of Note entity with its own sync. Reasons behind this hybrid design has been:
|
||||||
*
|
*
|
||||||
* - content can be quite large and it's not necessary to load it / fill memory for any note access even if we don't need a content, especially for bulk operations like search
|
* - content can be quite large, and it's not necessary to load it / fill memory for any note access even if we don't need a content, especially for bulk operations like search
|
||||||
* - changes in the note metadata or title should not trigger note content sync (so we keep separate utcDateModified and entity changes records)
|
* - changes in the note metadata or title should not trigger note content sync (so we keep separate utcDateModified and entity changes records)
|
||||||
* - but to the user note content and title changes are one and the same - single dateModified (so all changes must go through Note and content is not a separate entity)
|
* - but to the user note content and title changes are one and the same - single dateModified (so all changes must go through Note and content is not a separate entity)
|
||||||
*/
|
*/
|
||||||
|
@ -261,7 +261,7 @@ async function findSimilarNotes(noteId) {
|
|||||||
|
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
|
|
||||||
// when the title is very long then weight of each individual word should be lower
|
// when the title is very long then weight of each individual word should be lowered
|
||||||
// also pretty important in e.g. long URLs in label values
|
// also pretty important in e.g. long URLs in label values
|
||||||
const lengthPenalization = 1 / Math.pow(text.length, 0.3);
|
const lengthPenalization = 1 / Math.pow(text.length, 0.3);
|
||||||
|
|
||||||
@ -448,7 +448,7 @@ async function findSimilarNotes(noteId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Point of this is to break up long running sync process to avoid blocking
|
* 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/
|
* see https://snyk.io/blog/nodejs-how-even-quick-async-functions-can-block-the-event-loop-starve-io/
|
||||||
*/
|
*/
|
||||||
function setImmediatePromise() {
|
function setImmediatePromise() {
|
||||||
|
@ -89,7 +89,7 @@ class AppContext extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {Promise<void>} */
|
/** @returns {Promise<void>} */
|
||||||
triggerEvent(name, data) {
|
triggerEvent(name, data = {}) {
|
||||||
return this.handleEvent(name, data);
|
return this.handleEvent(name, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,11 +4,11 @@ import utils from '../services/utils.js';
|
|||||||
* Abstract class for all components in the Trilium's frontend.
|
* Abstract class for all components in the Trilium's frontend.
|
||||||
*
|
*
|
||||||
* Contains also event implementation with following properties:
|
* Contains also event implementation with following properties:
|
||||||
* - event / command distribution is synchronous which among others mean that events are well ordered - event
|
* - event / command distribution is synchronous which among others mean that events are well-ordered - event
|
||||||
* which was sent out first will also be processed first by the component
|
* which was sent out first will also be processed first by the component
|
||||||
* - execution of the event / command is asynchronous - each component executes the event on its own without regard for
|
* - execution of the event / command is asynchronous - each component executes the event on its own without regard for
|
||||||
* other components.
|
* other components.
|
||||||
* - although the execution is async, we are collecting all the promises and therefore it is possible to wait until the
|
* - although the execution is async, we are collecting all the promises, and therefore it is possible to wait until the
|
||||||
* event / command is executed in all components - by simply awaiting the `triggerEvent()`.
|
* event / command is executed in all components - by simply awaiting the `triggerEvent()`.
|
||||||
*/
|
*/
|
||||||
export default class Component {
|
export default class Component {
|
||||||
@ -62,12 +62,12 @@ export default class Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {Promise<void>} */
|
/** @returns {Promise<void>} */
|
||||||
triggerEvent(name, data) {
|
triggerEvent(name, data = {}) {
|
||||||
return this.parent.triggerEvent(name, data);
|
return this.parent.triggerEvent(name, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @returns {Promise<void>} */
|
/** @returns {Promise<void>} */
|
||||||
handleEventInChildren(name, data) {
|
handleEventInChildren(name, data = {}) {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
for (const child of this.children) {
|
for (const child of this.children) {
|
||||||
|
@ -9,9 +9,6 @@ import hoistedNoteService from "../services/hoisted_note.js";
|
|||||||
import options from "../services/options.js";
|
import options from "../services/options.js";
|
||||||
|
|
||||||
class NoteContext extends Component {
|
class NoteContext extends Component {
|
||||||
/**
|
|
||||||
* @param {string|null} ntxId
|
|
||||||
*/
|
|
||||||
constructor(ntxId = null, hoistedNoteId = 'root', mainNtxId = null) {
|
constructor(ntxId = null, hoistedNoteId = 'root', mainNtxId = null) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ class FNote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getContent() {
|
async getContent() {
|
||||||
// we're not caching content since these objects are in froca and as such pretty long lived
|
// we're not caching content since these objects are in froca and as such pretty long-lived
|
||||||
const note = await server.get(`notes/${this.noteId}`);
|
const note = await server.get(`notes/${this.noteId}`);
|
||||||
|
|
||||||
return note.content;
|
return note.content;
|
||||||
|
@ -24,7 +24,7 @@ class ContextMenu {
|
|||||||
|
|
||||||
positionMenu() {
|
positionMenu() {
|
||||||
// code below tries to detect when dropdown would overflow from page
|
// code below tries to detect when dropdown would overflow from page
|
||||||
// in such case we'll position it above click coordinates so it will fit into client
|
// in such case we'll position it above click coordinates, so it will fit into client
|
||||||
|
|
||||||
const CONTEXT_MENU_PADDING = 5; // How many pixels to pad context menu from edge of screen
|
const CONTEXT_MENU_PADDING = 5; // How many pixels to pad context menu from edge of screen
|
||||||
const CONTEXT_MENU_OFFSET = 0; // How many pixels to offset context menu by relative to cursor, see #3157
|
const CONTEXT_MENU_OFFSET = 0; // How many pixels to offset context menu by relative to cursor, see #3157
|
||||||
|
@ -19,7 +19,7 @@ export default class LauncherContextMenu {
|
|||||||
x: e.pageX,
|
x: e.pageX,
|
||||||
y: e.pageY,
|
y: e.pageY,
|
||||||
items: await this.getMenuItems(),
|
items: await this.getMenuItems(),
|
||||||
selectMenuItemHandler: (item, e) => this.selectMenuItemHandler(item, e)
|
selectMenuItemHandler: (item, e) => this.selectMenuItemHandler(item)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export default class TreeContextMenu {
|
|||||||
x: e.pageX,
|
x: e.pageX,
|
||||||
y: e.pageY,
|
y: e.pageY,
|
||||||
items: await this.getMenuItems(),
|
items: await this.getMenuItems(),
|
||||||
selectMenuItemHandler: (item, e) => this.selectMenuItemHandler(item, e)
|
selectMenuItemHandler: (item, e) => this.selectMenuItemHandler(item)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ function lex(str) {
|
|||||||
finishWord(i - 1);
|
finishWord(i - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// it's a quote but within other kind of quotes so it's valid as a literal character
|
// it's a quote but within other kind of quotes, so it's valid as a literal character
|
||||||
currentWord += chr;
|
currentWord += chr;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
@ -36,7 +36,7 @@ function isAffecting(attrRow, affectedNote) {
|
|||||||
const attrNote = froca.notes[attrRow.noteId];
|
const attrNote = froca.notes[attrRow.noteId];
|
||||||
|
|
||||||
if (!attrNote) {
|
if (!attrNote) {
|
||||||
// the note (owner of the attribute) is not even loaded into the cache so it should not affect anything else
|
// the note (owner of the attribute) is not even loaded into the cache, so it should not affect anything else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ async function pasteAfter(afterBranchId) {
|
|||||||
await branchService.cloneNoteAfter(clipboardNote.noteId, afterBranchId);
|
await branchService.cloneNoteAfter(clipboardNote.noteId, afterBranchId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy will keep clipboardBranchIds and clipboardMode so it's possible to paste into multiple places
|
// copy will keep clipboardBranchIds and clipboardMode, so it's possible to paste into multiple places
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
toastService.throwError(`Unrecognized clipboard mode=${clipboardMode}`);
|
toastService.throwError(`Unrecognized clipboard mode=${clipboardMode}`);
|
||||||
|
@ -7,20 +7,20 @@
|
|||||||
*
|
*
|
||||||
* @source underscore.js
|
* @source underscore.js
|
||||||
* @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
|
* @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
|
||||||
* @param {Function} function to wrap
|
* @param {Function} func to wrap
|
||||||
* @param {Number} timeout in ms (`100`)
|
* @param {Number} waitMs in ms (`100`)
|
||||||
* @param {Boolean} whether to execute at the beginning (`false`)
|
* @param {Boolean} immediate whether to execute at the beginning (`false`)
|
||||||
* @api public
|
* @api public
|
||||||
*/
|
*/
|
||||||
function debounce(func, wait_ms, immediate){
|
function debounce(func, waitMs, immediate) {
|
||||||
var timeout, args, context, timestamp, result;
|
var timeout, args, context, timestamp, result;
|
||||||
if (null == wait_ms) wait_ms = 100;
|
if (null == waitMs) waitMs = 100;
|
||||||
|
|
||||||
function later() {
|
function later() {
|
||||||
var last = Date.now() - timestamp;
|
var last = Date.now() - timestamp;
|
||||||
|
|
||||||
if (last < wait_ms && last >= 0) {
|
if (last < waitMs && last >= 0) {
|
||||||
timeout = setTimeout(later, wait_ms - last);
|
timeout = setTimeout(later, waitMs - last);
|
||||||
} else {
|
} else {
|
||||||
timeout = null;
|
timeout = null;
|
||||||
if (!immediate) {
|
if (!immediate) {
|
||||||
@ -28,14 +28,14 @@ function debounce(func, wait_ms, immediate){
|
|||||||
context = args = null;
|
context = args = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
var debounced = function(){
|
var debounced = function(){
|
||||||
context = this;
|
context = this;
|
||||||
args = arguments;
|
args = arguments;
|
||||||
timestamp = Date.now();
|
timestamp = Date.now();
|
||||||
var callNow = immediate && !timeout;
|
var callNow = immediate && !timeout;
|
||||||
if (!timeout) timeout = setTimeout(later, wait_ms);
|
if (!timeout) timeout = setTimeout(later, waitMs);
|
||||||
if (callNow) {
|
if (callNow) {
|
||||||
result = func.apply(context, args);
|
result = func.apply(context, args);
|
||||||
context = args = null;
|
context = args = null;
|
||||||
@ -62,7 +62,7 @@ function debounce(func, wait_ms, immediate){
|
|||||||
};
|
};
|
||||||
|
|
||||||
return debounced;
|
return debounced;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Adds compatibility for ES modules
|
// Adds compatibility for ES modules
|
||||||
debounce.debounce = debounce;
|
debounce.debounce = debounce;
|
||||||
|
@ -85,7 +85,7 @@ function processNoteChange(loadResults, ec) {
|
|||||||
const note = froca.notes[ec.entityId];
|
const note = froca.notes[ec.entityId];
|
||||||
|
|
||||||
if (!note) {
|
if (!note) {
|
||||||
// if this note has not been requested before then it's not part of froca's cached subset and
|
// if this note has not been requested before then it's not part of froca's cached subset, and
|
||||||
// we're not interested in it
|
// we're not interested in it
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
|||||||
*
|
*
|
||||||
* @method
|
* @method
|
||||||
* @param {string} script - script to be executed on the backend
|
* @param {string} script - script to be executed on the backend
|
||||||
* @param {Array.<?>} params - list of parameters to the anonymous function to be send to backend
|
* @param {Array.<?>} params - list of parameters to the anonymous function to be sent to backend
|
||||||
* @returns {Promise<*>} return value of the executed function on the backend
|
* @returns {Promise<*>} return value of the executed function on the backend
|
||||||
*/
|
*/
|
||||||
this.runOnBackend = async (script, params = []) => {
|
this.runOnBackend = async (script, params = []) => {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import appContext from "../components/app_context.js";
|
import appContext from "../components/app_context.js";
|
||||||
import utils from "./utils.js";
|
|
||||||
import protectedSessionHolder from "./protected_session_holder.js";
|
import protectedSessionHolder from "./protected_session_holder.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
import ws from "./ws.js";
|
import ws from "./ws.js";
|
||||||
@ -15,7 +14,7 @@ async function createNote(parentNotePath, options = {}) {
|
|||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
// if isProtected isn't available (user didn't enter password yet), then note is created as unencrypted
|
// if isProtected isn't available (user didn't enter password yet), then note is created as unencrypted
|
||||||
// but this is quite weird since user doesn't see WHERE the note is being created so it shouldn't occur often
|
// but this is quite weird since user doesn't see WHERE the note is being created, so it shouldn't occur often
|
||||||
if (!options.isProtected || !protectedSessionHolder.isProtectedSessionAvailable()) {
|
if (!options.isProtected || !protectedSessionHolder.isProtectedSessionAvailable()) {
|
||||||
options.isProtected = false;
|
options.isProtected = false;
|
||||||
}
|
}
|
||||||
|
@ -58,11 +58,11 @@ function downloadNoteRevision(noteId, noteRevisionId) {
|
|||||||
*/
|
*/
|
||||||
function getUrlForDownload(url) {
|
function getUrlForDownload(url) {
|
||||||
if (utils.isElectron()) {
|
if (utils.isElectron()) {
|
||||||
// electron needs absolute URL so we extract current host, port, protocol
|
// electron needs absolute URL, so we extract current host, port, protocol
|
||||||
return `${getHost()}/${url}`;
|
return `${getHost()}/${url}`;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// web server can be deployed on subdomain so we need to use relative path
|
// web server can be deployed on subdomain, so we need to use relative path
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ export default class SpacedUpdate {
|
|||||||
this.changed = false;
|
this.changed = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// update not triggered but changes are still pending so we need to schedule another check
|
// update not triggered but changes are still pending, so we need to schedule another check
|
||||||
this.scheduleUpdate();
|
this.scheduleUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import ws from './ws.js';
|
import ws from './ws.js';
|
||||||
import utils from './utils.js';
|
import utils from './utils.js';
|
||||||
import server from './server.js';
|
|
||||||
import froca from './froca.js';
|
import froca from './froca.js';
|
||||||
import hoistedNoteService from '../services/hoisted_note.js';
|
import hoistedNoteService from '../services/hoisted_note.js';
|
||||||
import appContext from "../components/app_context.js";
|
import appContext from "../components/app_context.js";
|
||||||
|
@ -3,7 +3,7 @@ function reloadFrontendApp(reason) {
|
|||||||
logInfo(`Frontend app reload: ${reason}`);
|
logInfo(`Frontend app reload: ${reason}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.location.reload(true);
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDate(str) {
|
function parseDate(str) {
|
||||||
@ -314,7 +314,7 @@ function initHelpDropdown($el) {
|
|||||||
const $dropdownMenu = $el.find('.help-dropdown .dropdown-menu');
|
const $dropdownMenu = $el.find('.help-dropdown .dropdown-menu');
|
||||||
$dropdownMenu.on('click', e => e.stopPropagation());
|
$dropdownMenu.on('click', e => e.stopPropagation());
|
||||||
|
|
||||||
// previous propagation stop will also block help buttons from being opened so we need to re-init for this element
|
// previous propagation stop will also block help buttons from being opened, so we need to re-init for this element
|
||||||
initHelpButtons($dropdownMenu);
|
initHelpButtons($dropdownMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,6 +346,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget {
|
|||||||
|
|
||||||
this.$editor.on("click", e => this.handleEditorClick(e));
|
this.$editor.on("click", e => this.handleEditorClick(e));
|
||||||
|
|
||||||
|
/** @property {BalloonEditor} */
|
||||||
this.textEditor = await BalloonEditor.create(this.$editor[0], editorConfig);
|
this.textEditor = await BalloonEditor.create(this.$editor[0], editorConfig);
|
||||||
this.textEditor.model.document.on('change:data', () => this.dataChanged());
|
this.textEditor.model.document.on('change:data', () => this.dataChanged());
|
||||||
this.textEditor.editing.view.document.on('enter', (event, data) => {
|
this.textEditor.editing.view.document.on('enter', (event, data) => {
|
||||||
|
@ -112,7 +112,7 @@ export default class SplitNoteContainer extends FlexContainer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* widget.hasBeenAlreadyShown is intended for lazy loading of cached tabs - initial note switches of new tabs
|
* widget.hasBeenAlreadyShown is intended for lazy loading of cached tabs - initial note switches of new tabs
|
||||||
* are not executed, we're waiting for the first tab activation and then we update the tab. After this initial
|
* are not executed, we're waiting for the first tab activation, and then we update the tab. After this initial
|
||||||
* activation further note switches are always propagated to the tabs.
|
* activation further note switches are always propagated to the tabs.
|
||||||
*/
|
*/
|
||||||
handleEventInChildren(name, data) {
|
handleEventInChildren(name, data) {
|
||||||
|
@ -99,7 +99,7 @@ export default class AddLinkDialog extends BasicWidget {
|
|||||||
|
|
||||||
this.$addLinkTitleSettings.find('input[type=radio]').on('change', e => this.updateTitleSettingsVisibility(e));
|
this.$addLinkTitleSettings.find('input[type=radio]').on('change', e => this.updateTitleSettingsVisibility(e));
|
||||||
|
|
||||||
// with selection hyper link is implied
|
// with selection hyperlink is implied
|
||||||
if (this.textTypeWidget.hasSelection()) {
|
if (this.textTypeWidget.hasSelection()) {
|
||||||
this.$addLinkTitleSettings.find("input[value='hyper-link']").prop("checked", true);
|
this.$addLinkTitleSettings.find("input[value='hyper-link']").prop("checked", true);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import server from "../../services/server.js";
|
import server from "../../services/server.js";
|
||||||
import utils from "../../services/utils.js";
|
|
||||||
import BasicWidget from "../basic_widget.js";
|
import BasicWidget from "../basic_widget.js";
|
||||||
|
|
||||||
const TPL = `
|
const TPL = `
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import utils from "../../services/utils.js";
|
|
||||||
import BasicWidget from "../basic_widget.js";
|
import BasicWidget from "../basic_widget.js";
|
||||||
|
|
||||||
const TPL = `
|
const TPL = `
|
||||||
|
@ -98,7 +98,7 @@ export default class IncludeNoteDialog extends BasicWidget {
|
|||||||
const boxSize = $("input[name='include-note-box-size']:checked").val();
|
const boxSize = $("input[name='include-note-box-size']:checked").val();
|
||||||
|
|
||||||
if (note.type === 'image') {
|
if (note.type === 'image') {
|
||||||
// there's no benefit to use insert note functionlity for images
|
// there's no benefit to use insert note functionlity for images,
|
||||||
// so we'll just add an IMG tag
|
// so we'll just add an IMG tag
|
||||||
this.textTypeWidget.addImage(noteId);
|
this.textTypeWidget.addImage(noteId);
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ export default class InfoDialog extends BasicWidget {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.resolve = null;
|
this.resolve = null;
|
||||||
this.$originallyFocused = null; // element focused before the dialog was opened so we can return to it afterwards
|
this.$originallyFocused = null; // element focused before the dialog was opened, so we can return to it afterwards
|
||||||
}
|
}
|
||||||
|
|
||||||
doRender() {
|
doRender() {
|
||||||
|
@ -239,8 +239,8 @@ export default class NoteRevisionsDialog extends BasicWidget {
|
|||||||
}
|
}
|
||||||
else if (revisionItem.type === 'image') {
|
else if (revisionItem.type === 'image') {
|
||||||
this.$content.html($("<img>")
|
this.$content.html($("<img>")
|
||||||
// reason why we put this inline as base64 is that we do not want to let user to copy this
|
// reason why we put this inline as base64 is that we do not want to let user copy this
|
||||||
// as a URL to be used in a note. Instead if they copy and paste it into a note, it will be a uploaded as a new note
|
// as a URL to be used in a note. Instead, if they copy and paste it into a note, it will be an uploaded as a new note
|
||||||
.attr("src", `data:${note.mime};base64,${fullNoteRevision.content}`)
|
.attr("src", `data:${note.mime};base64,${fullNoteRevision.content}`)
|
||||||
.css("max-width", "100%")
|
.css("max-width", "100%")
|
||||||
.css("max-height", "100%"));
|
.css("max-height", "100%"));
|
||||||
|
@ -69,8 +69,8 @@ export default class FindInCode {
|
|||||||
let curChar = 0;
|
let curChar = 0;
|
||||||
let curMatch = null;
|
let curMatch = null;
|
||||||
findResult = [];
|
findResult = [];
|
||||||
// All those markText take several seconds on eg this ~500-line
|
// All those markText take several seconds on e.g. this ~500-line
|
||||||
// script, batch them inside an operation so they become
|
// script, batch them inside an operation, so they become
|
||||||
// unnoticeable. Alternatively, an overlay could be used, see
|
// unnoticeable. Alternatively, an overlay could be used, see
|
||||||
// https://codemirror.net/addon/search/match-highlighter.js ?
|
// https://codemirror.net/addon/search/match-highlighter.js ?
|
||||||
codeEditor.operation(() => {
|
codeEditor.operation(() => {
|
||||||
|
@ -14,9 +14,9 @@ export default class FindInText {
|
|||||||
const selection = textEditor.model.document.selection;
|
const selection = textEditor.model.document.selection;
|
||||||
const range = selection.getFirstRange();
|
const range = selection.getFirstRange();
|
||||||
|
|
||||||
|
// FIXME
|
||||||
for (const item of range.getItems()) {
|
for (const item of range.getItems()) {
|
||||||
// Fill in the findbox with the current selection if
|
// Fill in the findbox with the current selection if any
|
||||||
// any
|
|
||||||
return item.data;
|
return item.data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ import options from "../services/options.js";
|
|||||||
import protectedSessionHolder from "../services/protected_session_holder.js";
|
import protectedSessionHolder from "../services/protected_session_holder.js";
|
||||||
import dialogService from "../services/dialog.js";
|
import dialogService from "../services/dialog.js";
|
||||||
import shortcutService from "../services/shortcuts.js";
|
import shortcutService from "../services/shortcuts.js";
|
||||||
import LauncherContextMenu from "../menus/launcher_context_menu.js";
|
|
||||||
|
|
||||||
const TPL = `
|
const TPL = `
|
||||||
<div class="tree-wrapper">
|
<div class="tree-wrapper">
|
||||||
@ -915,7 +914,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
if (expand) {
|
if (expand) {
|
||||||
await parentNode.setExpanded(true, {noAnimation: true});
|
await parentNode.setExpanded(true, {noAnimation: true});
|
||||||
|
|
||||||
// although previous line should set the expanded status, it seems to happen asynchronously
|
// although previous line should set the expanded status, it seems to happen asynchronously,
|
||||||
// so we need to make sure it is set properly before calling updateNode which uses this flag
|
// so we need to make sure it is set properly before calling updateNode which uses this flag
|
||||||
const branch = froca.getBranch(parentNode.data.branchId);
|
const branch = froca.getBranch(parentNode.data.branchId);
|
||||||
branch.isExpanded = true;
|
branch.isExpanded = true;
|
||||||
@ -925,7 +924,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
|
|
||||||
let foundChildNode = this.findChildNode(parentNode, childNoteId);
|
let foundChildNode = this.findChildNode(parentNode, childNoteId);
|
||||||
|
|
||||||
if (!foundChildNode) { // note might be recently created so we'll force reload and try again
|
if (!foundChildNode) { // note might be recently created, so we'll force reload and try again
|
||||||
await parentNode.load(true);
|
await parentNode.load(true);
|
||||||
|
|
||||||
foundChildNode = this.findChildNode(parentNode, childNoteId);
|
foundChildNode = this.findChildNode(parentNode, childNoteId);
|
||||||
@ -933,7 +932,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
if (!foundChildNode) {
|
if (!foundChildNode) {
|
||||||
if (logErrors) {
|
if (logErrors) {
|
||||||
// besides real errors this can be also caused by hiding of e.g. included images
|
// besides real errors this can be also caused by hiding of e.g. included images
|
||||||
// these are real notes with real notePath, user can display them in a detail
|
// these are real notes with real notePath, user can display them in a detail,
|
||||||
// but they don't have a node in the tree
|
// but they don't have a node in the tree
|
||||||
|
|
||||||
const childNote = await froca.getNote(childNoteId);
|
const childNote = await froca.getNote(childNoteId);
|
||||||
|
@ -54,7 +54,7 @@ export default class QuickSearchWidget extends BasicWidget {
|
|||||||
|
|
||||||
if(utils.isMobile()) {
|
if(utils.isMobile()) {
|
||||||
this.$searchString.keydown(e =>{
|
this.$searchString.keydown(e =>{
|
||||||
if(e.which==13) {
|
if(e.which === 13) {
|
||||||
if (this.$dropdownMenu.is(":visible")) {
|
if (this.$dropdownMenu.is(":visible")) {
|
||||||
this.search(); // just update already visible dropdown
|
this.search(); // just update already visible dropdown
|
||||||
} else {
|
} else {
|
||||||
@ -128,7 +128,7 @@ export default class QuickSearchWidget extends BasicWidget {
|
|||||||
this.$dropdownToggle.dropdown("hide");
|
this.$dropdownToggle.dropdown("hide");
|
||||||
|
|
||||||
if (!e.target || e.target.nodeName !== 'A') {
|
if (!e.target || e.target.nodeName !== 'A') {
|
||||||
// click on the link is handled by link handling but we want the whole item clickable
|
// click on the link is handled by link handling, but we want the whole item clickable
|
||||||
appContext.tabManager.getActiveContext().setNote(note.noteId);
|
appContext.tabManager.getActiveContext().setNote(note.noteId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
||||||
import treeService from "../services/tree.js";
|
|
||||||
import linkService from "../services/link.js";
|
|
||||||
import hoistedNoteService from "../services/hoisted_note.js";
|
|
||||||
import server from "../services/server.js";
|
import server from "../services/server.js";
|
||||||
import toastService from "../services/toast.js";
|
|
||||||
|
|
||||||
const TPL = `
|
const TPL = `
|
||||||
<div class="sql-table-schemas-widget">
|
<div class="sql-table-schemas-widget">
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
* Table of contents widget
|
* Table of contents widget
|
||||||
* (c) Antonio Tejada 2022
|
* (c) Antonio Tejada 2022
|
||||||
*
|
*
|
||||||
* By design there's no support for non-sensical or malformed constructs:
|
* By design there's no support for nonsensical or malformed constructs:
|
||||||
* - headings inside elements (eg Trilium allows headings inside tables, but
|
* - headings inside elements (e.g. Trilium allows headings inside tables, but
|
||||||
* not inside lists)
|
* not inside lists)
|
||||||
* - nested headings when using raw HTML <H2><H3></H3></H2>
|
* - nested headings when using raw HTML <H2><H3></H3></H2>
|
||||||
* - malformed headings when using raw HTML <H2></H3></H2><H3>
|
* - malformed headings when using raw HTML <H2></H3></H2><H3>
|
||||||
@ -52,7 +52,7 @@ const TPL = `<div class="toc-widget">
|
|||||||
* @param {Element} parent Parent node to find a headingIndex'th in.
|
* @param {Element} parent Parent node to find a headingIndex'th in.
|
||||||
* @param {uint} headingIndex Index for the heading
|
* @param {uint} headingIndex Index for the heading
|
||||||
* @returns {Element|null} Heading node with the given index, null couldn't be
|
* @returns {Element|null} Heading node with the given index, null couldn't be
|
||||||
* found (ie malformed like nested headings, etc)
|
* found (ie malformed like nested headings, etc.)
|
||||||
*/
|
*/
|
||||||
function findHeadingNodeByIndex(parent, headingIndex) {
|
function findHeadingNodeByIndex(parent, headingIndex) {
|
||||||
let headingNode = null;
|
let headingNode = null;
|
||||||
@ -61,7 +61,7 @@ function findHeadingNodeByIndex(parent, headingIndex) {
|
|||||||
|
|
||||||
// Headings appear as flattened top level children in the CKEditor
|
// Headings appear as flattened top level children in the CKEditor
|
||||||
// document named as "heading" plus the level, eg "heading2",
|
// document named as "heading" plus the level, eg "heading2",
|
||||||
// "heading3", "heading2", etc and not nested wrt the heading level. If
|
// "heading3", "heading2", etc. and not nested wrt the heading level. If
|
||||||
// a heading node is found, decrement the headingIndex until zero is
|
// a heading node is found, decrement the headingIndex until zero is
|
||||||
// reached
|
// reached
|
||||||
if (child.name.startsWith("heading")) {
|
if (child.name.startsWith("heading")) {
|
||||||
|
@ -144,7 +144,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
/**
|
/**
|
||||||
* called to populate the widget container with the note content
|
* called to populate the widget container with the note content
|
||||||
*
|
*
|
||||||
* @param {note} note
|
* @param {FNote} note
|
||||||
*/
|
*/
|
||||||
async doRefresh(note) {
|
async doRefresh(note) {
|
||||||
// see if note changed, since we do not get a new class for a new note
|
// see if note changed, since we do not get a new class for a new note
|
||||||
@ -219,7 +219,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
collaborators: []
|
collaborators: []
|
||||||
};
|
};
|
||||||
|
|
||||||
// files are expected in an array when loading. they are stored as an key-index object
|
// files are expected in an array when loading. they are stored as a key-index object
|
||||||
// see example for loading here:
|
// see example for loading here:
|
||||||
// https://github.com/excalidraw/excalidraw/blob/c5a7723185f6ca05e0ceb0b0d45c4e3fbcb81b2a/src/packages/excalidraw/example/App.js#L68
|
// https://github.com/excalidraw/excalidraw/blob/c5a7723185f6ca05e0ceb0b0d45c4e3fbcb81b2a/src/packages/excalidraw/example/App.js#L68
|
||||||
const fileArray = [];
|
const fileArray = [];
|
||||||
|
@ -122,13 +122,13 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
this.watchdog = new EditorWatchdog(BalloonEditor, {
|
this.watchdog = new EditorWatchdog(BalloonEditor, {
|
||||||
// An average number of milliseconds between the last editor errors (defaults to 5000).
|
// An average number of milliseconds between the last editor errors (defaults to 5000).
|
||||||
// When the period of time between errors is lower than that and the crashNumberLimit
|
// When the period of time between errors is lower than that and the crashNumberLimit
|
||||||
// is also reached, the watchdog changes its state to crashedPermanently and it stops
|
// is also reached, the watchdog changes its state to crashedPermanently, and it stops
|
||||||
// restarting the editor. This prevents an infinite restart loop.
|
// restarting the editor. This prevents an infinite restart loop.
|
||||||
minimumNonErrorTimePeriod: 5000,
|
minimumNonErrorTimePeriod: 5000,
|
||||||
// A threshold specifying the number of errors (defaults to 3).
|
// A threshold specifying the number of errors (defaults to 3).
|
||||||
// After this limit is reached and the time between last errors
|
// After this limit is reached and the time between last errors
|
||||||
// is shorter than minimumNonErrorTimePeriod, the watchdog changes
|
// is shorter than minimumNonErrorTimePeriod, the watchdog changes
|
||||||
// its state to crashedPermanently and it stops restarting the editor.
|
// its state to crashedPermanently, and it stops restarting the editor.
|
||||||
// This prevents an infinite restart loop.
|
// This prevents an infinite restart loop.
|
||||||
crashNumberLimit: 3,
|
crashNumberLimit: 3,
|
||||||
// A minimum number of milliseconds between saving the editor data internally (defaults to 5000).
|
// A minimum number of milliseconds between saving the editor data internally (defaults to 5000).
|
||||||
|
@ -56,7 +56,7 @@ class ImageTypeWidget extends TypeWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (utils.isElectron()) {
|
if (utils.isElectron()) {
|
||||||
// for browser we want to let the native menu
|
// for browser, we want to let the native menu
|
||||||
this.$imageView.on('contextmenu', e => {
|
this.$imageView.on('contextmenu', e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import server from "../../../services/server.js";
|
import server from "../../../services/server.js";
|
||||||
import toastService from "../../../services/toast.js";
|
import toastService from "../../../services/toast.js";
|
||||||
import NoteContextAwareWidget from "../../note_context_aware_widget.js";
|
import NoteContextAwareWidget from "../../note_context_aware_widget.js";
|
||||||
import attributeService from "../../../services/attributes.js";
|
|
||||||
|
|
||||||
export default class OptionsWidget extends NoteContextAwareWidget {
|
export default class OptionsWidget extends NoteContextAwareWidget {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -11,10 +11,10 @@ function getFontCss(req, res) {
|
|||||||
|
|
||||||
const optionsMap = optionService.getOptionsMap();
|
const optionsMap = optionService.getOptionsMap();
|
||||||
|
|
||||||
const mainFontFamilyOverridden = optionsMap.mainFontFamily != 'theme';
|
const mainFontFamilyOverridden = optionsMap.mainFontFamily !== 'theme';
|
||||||
const treeFontFamilyOverridden = optionsMap.treeFontFamily != 'theme';
|
const treeFontFamilyOverridden = optionsMap.treeFontFamily !== 'theme';
|
||||||
const detailFontFamilyOverridden = optionsMap.detailFontFamily != 'theme';
|
const detailFontFamilyOverridden = optionsMap.detailFontFamily !== 'theme';
|
||||||
const monospaceFontFamilyOverridden = optionsMap.monospaceFontFamily != 'theme';
|
const monospaceFontFamilyOverridden = optionsMap.monospaceFontFamily !== 'theme';
|
||||||
|
|
||||||
// using body to be more specific than themes' :root
|
// using body to be more specific than themes' :root
|
||||||
let style = 'body {';
|
let style = 'body {';
|
||||||
|
@ -30,6 +30,11 @@ function buildDescendantCountMap() {
|
|||||||
return noteIdToCountMap;
|
return noteIdToCountMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {BNote} note
|
||||||
|
* @param {int} depth
|
||||||
|
* @returns {string[]} noteIds
|
||||||
|
*/
|
||||||
function getNeighbors(note, depth) {
|
function getNeighbors(note, depth) {
|
||||||
if (depth === 0) {
|
if (depth === 0) {
|
||||||
return [];
|
return [];
|
||||||
@ -157,7 +162,7 @@ function getLinkMap(req) {
|
|||||||
|
|
||||||
function getTreeMap(req) {
|
function getTreeMap(req) {
|
||||||
const mapRootNote = becca.getNote(req.params.noteId);
|
const mapRootNote = becca.getNote(req.params.noteId);
|
||||||
// if the map root itself has ignore (journal typically) then there wouldn't be anything to display so
|
// if the map root itself has ignore (journal typically) then there wouldn't be anything to display, so
|
||||||
// we'll just ignore it
|
// we'll just ignore it
|
||||||
const ignoreExcludeFromNoteMap = mapRootNote.hasLabel('excludeFromNoteMap');
|
const ignoreExcludeFromNoteMap = mapRootNote.hasLabel('excludeFromNoteMap');
|
||||||
const subtree = mapRootNote.getSubtree({
|
const subtree = mapRootNote.getSubtree({
|
||||||
@ -259,6 +264,7 @@ function findExcerpts(sourceNote, referencedNoteId) {
|
|||||||
centerEl = centerEl.parentElement;
|
centerEl = centerEl.parentElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var {HTMLElement[]} */
|
||||||
const excerptEls = [centerEl];
|
const excerptEls = [centerEl];
|
||||||
let excerptLength = centerEl.textContent.length;
|
let excerptLength = centerEl.textContent.length;
|
||||||
let left = centerEl;
|
let left = centerEl;
|
||||||
|
@ -21,7 +21,7 @@ async function testSync() {
|
|||||||
|
|
||||||
await syncService.login();
|
await syncService.login();
|
||||||
|
|
||||||
// login was successful so we'll kick off sync now
|
// login was successful, so we'll kick off sync now
|
||||||
// this is important in case when sync server has been just initialized
|
// this is important in case when sync server has been just initialized
|
||||||
syncService.sync();
|
syncService.sync();
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ const BUILTIN_ATTRIBUTES = require("./builtin_attributes");
|
|||||||
const ATTRIBUTE_TYPES = [ 'label', 'relation' ];
|
const ATTRIBUTE_TYPES = [ 'label', 'relation' ];
|
||||||
|
|
||||||
/** @returns {BNote[]} */
|
/** @returns {BNote[]} */
|
||||||
function getNotesWithLabel(name, value) {
|
function getNotesWithLabel(name, value = undefined) {
|
||||||
const query = formatAttrForSearch({type: 'label', name, value}, true);
|
const query = formatAttrForSearch({type: 'label', name, value}, value !== undefined);
|
||||||
return searchService.searchNotes(query, {
|
return searchService.searchNotes(query, {
|
||||||
includeArchivedNotes: true,
|
includeArchivedNotes: true,
|
||||||
ignoreHoistedNote: true
|
ignoreHoistedNote: true
|
||||||
|
@ -336,7 +336,7 @@ class ConsistencyChecks {
|
|||||||
({noteId, isProtected, type, mime}) => {
|
({noteId, isProtected, type, mime}) => {
|
||||||
if (this.autoFix) {
|
if (this.autoFix) {
|
||||||
// it might be possible that the note_content is not available only because of the interrupted
|
// it might be possible that the note_content is not available only because of the interrupted
|
||||||
// sync and it will come later. It's therefore important to guarantee that this artifical
|
// sync, and it will come later. It's therefore important to guarantee that this artifical
|
||||||
// record won't overwrite the real one coming from the sync.
|
// record won't overwrite the real one coming from the sync.
|
||||||
const fakeDate = "2000-01-01 00:00:00Z";
|
const fakeDate = "2000-01-01 00:00:00Z";
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ function utcNowDateTime() {
|
|||||||
return utcDateTimeStr(new Date());
|
return utcDateTimeStr(new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
// CLS date time is important in web deployments - server often runs in different time zone than user is located in
|
// CLS date time is important in web deployments - server often runs in different time zone than user is located in,
|
||||||
// so we'd prefer client timezone to be used to record local dates. For this reason requests from client contain
|
// so we'd prefer client timezone to be used to record local dates. For this reason requests from client contain
|
||||||
// "trilium-local-now-datetime" header which is then stored in CLS
|
// "trilium-local-now-datetime" header which is then stored in CLS
|
||||||
function localNowDateTime() {
|
function localNowDateTime() {
|
||||||
|
@ -21,6 +21,8 @@ const ValidationError = require("../../errors/validation_error");
|
|||||||
* @param {TaskContext} taskContext
|
* @param {TaskContext} taskContext
|
||||||
* @param {BBranch} branch
|
* @param {BBranch} branch
|
||||||
* @param {string} format - 'html' or 'markdown'
|
* @param {string} format - 'html' or 'markdown'
|
||||||
|
* @param {object} res - express response
|
||||||
|
* @param {boolean} setHeaders
|
||||||
*/
|
*/
|
||||||
async function exportToZip(taskContext, branch, format, res, setHeaders = true) {
|
async function exportToZip(taskContext, branch, format, res, setHeaders = true) {
|
||||||
if (!['html', 'markdown'].includes(format)) {
|
if (!['html', 'markdown'].includes(format)) {
|
||||||
|
@ -207,7 +207,7 @@ function importEnex(taskContext, file, parentNote) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function updateDates(noteId, utcDateCreated, utcDateModified) {
|
function updateDates(noteId, utcDateCreated, utcDateModified) {
|
||||||
// it's difficult to force custom dateCreated and dateModified to Note entity so we do it post-creation with SQL
|
// it's difficult to force custom dateCreated and dateModified to Note entity, so we do it post-creation with SQL
|
||||||
sql.execute(`
|
sql.execute(`
|
||||||
UPDATE notes
|
UPDATE notes
|
||||||
SET dateCreated = ?,
|
SET dateCreated = ?,
|
||||||
|
@ -544,7 +544,7 @@ function saveLinks(note, content) {
|
|||||||
|
|
||||||
existingLinks.push(newLink);
|
existingLinks.push(newLink);
|
||||||
}
|
}
|
||||||
// else the link exists so we don't need to do anything
|
// else the link exists, so we don't need to do anything
|
||||||
}
|
}
|
||||||
|
|
||||||
// marking links as deleted if they are not present on the page anymore
|
// marking links as deleted if they are not present on the page anymore
|
||||||
|
@ -11,7 +11,7 @@ const syncOptions = require('./sync_options');
|
|||||||
function exec(opts) {
|
function exec(opts) {
|
||||||
const client = getClient(opts);
|
const client = getClient(opts);
|
||||||
|
|
||||||
// hack for cases where electron.net does not work but we don't want to set proxy
|
// hack for cases where electron.net does not work, but we don't want to set proxy
|
||||||
if (opts.proxy === 'noproxy') {
|
if (opts.proxy === 'noproxy') {
|
||||||
opts.proxy = null;
|
opts.proxy = null;
|
||||||
}
|
}
|
||||||
|
@ -66,8 +66,8 @@ function executeScript(script, params, startNoteId, currentNoteId, originEntityN
|
|||||||
const currentNote = becca.getNote(currentNoteId);
|
const currentNote = becca.getNote(currentNoteId);
|
||||||
const originEntity = becca.getEntity(originEntityName, originEntityId);
|
const originEntity = becca.getEntity(originEntityName, originEntityId);
|
||||||
|
|
||||||
// we're just executing an excerpt of the original frontend script in the backend context so we must
|
// we're just executing an excerpt of the original frontend script in the backend context, so we must
|
||||||
// override normal note's content and it's mime type / script environment
|
// override normal note's content, and it's mime type / script environment
|
||||||
const backendOverrideContent = `return (${script}\r\n)(${getParams(params)})`;
|
const backendOverrideContent = `return (${script}\r\n)(${getParams(params)})`;
|
||||||
|
|
||||||
const bundle = getScriptBundle(currentNote, true, null, [], backendOverrideContent);
|
const bundle = getScriptBundle(currentNote, true, null, [], backendOverrideContent);
|
||||||
|
@ -17,6 +17,11 @@ class NoteFlatTextExp extends Expression {
|
|||||||
const beccaService = require('../../../becca/becca_service');
|
const beccaService = require('../../../becca/becca_service');
|
||||||
const resultNoteSet = new NoteSet();
|
const resultNoteSet = new NoteSet();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {BNote} note
|
||||||
|
* @param {string[]} tokens
|
||||||
|
* @param {string[]} path
|
||||||
|
*/
|
||||||
function searchDownThePath(note, tokens, path) {
|
function searchDownThePath(note, tokens, path) {
|
||||||
if (tokens.length === 0) {
|
if (tokens.length === 0) {
|
||||||
const retPath = beccaService.getSomePath(note, path);
|
const retPath = beccaService.getSomePath(note, path);
|
||||||
|
@ -230,6 +230,7 @@ function parseQueryToExpression(query, searchContext) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} query
|
* @param {string} query
|
||||||
|
* @param {object} params - see SearchContext
|
||||||
* @returns {BNote[]}
|
* @returns {BNote[]}
|
||||||
*/
|
*/
|
||||||
function searchNotes(query, params = {}) {
|
function searchNotes(query, params = {}) {
|
||||||
@ -299,7 +300,7 @@ function highlightSearchResults(searchResults, highlightedTokens) {
|
|||||||
// < and > are used for marking <small> and </small>
|
// < and > are used for marking <small> and </small>
|
||||||
highlightedTokens = highlightedTokens.map(token => token.replace('/[<\{\}]/g', ''));
|
highlightedTokens = highlightedTokens.map(token => token.replace('/[<\{\}]/g', ''));
|
||||||
|
|
||||||
// sort by the longest so we first highlight longest matches
|
// sort by the longest, so we first highlight the longest matches
|
||||||
highlightedTokens.sort((a, b) => a.length > b.length ? -1 : 1);
|
highlightedTokens.sort((a, b) => a.length > b.length ? -1 : 1);
|
||||||
|
|
||||||
for (const result of searchResults) {
|
for (const result of searchResults) {
|
||||||
|
@ -47,7 +47,7 @@ class SpacedUpdate {
|
|||||||
this.changed = false;
|
this.changed = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// update not triggered but changes are still pending so we need to schedule another check
|
// update not triggered but changes are still pending, so we need to schedule another check
|
||||||
this.scheduleUpdate();
|
this.scheduleUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ async function doLogin() {
|
|||||||
|
|
||||||
const lastSyncedPull = getLastSyncedPull();
|
const lastSyncedPull = getLastSyncedPull();
|
||||||
|
|
||||||
// this is important in a scenario where we setup the sync by manually copying the document
|
// this is important in a scenario where we set up the sync by manually copying the document
|
||||||
// lastSyncedPull then could be pretty off for the newly cloned client
|
// lastSyncedPull then could be pretty off for the newly cloned client
|
||||||
if (lastSyncedPull > resp.maxEntityChangeId) {
|
if (lastSyncedPull > resp.maxEntityChangeId) {
|
||||||
log.info(`Lowering last synced pull from ${lastSyncedPull} to ${resp.maxEntityChangeId}`);
|
log.info(`Lowering last synced pull from ${lastSyncedPull} to ${resp.maxEntityChangeId}`);
|
||||||
|
@ -21,7 +21,7 @@ module.exports = {
|
|||||||
isSyncSetup: () => {
|
isSyncSetup: () => {
|
||||||
const syncServerHost = get('syncServerHost');
|
const syncServerHost = get('syncServerHost');
|
||||||
|
|
||||||
// special value "disabled" is here to support use case where document is configured with sync server
|
// special value "disabled" is here to support use case where document is configured with sync server,
|
||||||
// and we need to override it with config from config.ini
|
// and we need to override it with config from config.ini
|
||||||
return !!syncServerHost && syncServerHost !== 'disabled';
|
return !!syncServerHost && syncServerHost !== 'disabled';
|
||||||
},
|
},
|
||||||
|
@ -85,7 +85,7 @@ function getExistingBranch(parentNoteId, childNoteId) {
|
|||||||
function checkTreeCycle(parentNoteId, childNoteId) {
|
function checkTreeCycle(parentNoteId, childNoteId) {
|
||||||
const subtreeNoteIds = [];
|
const subtreeNoteIds = [];
|
||||||
|
|
||||||
// we'll load the whole sub tree - because the cycle can start in one of the notes in the sub tree
|
// we'll load the whole subtree - because the cycle can start in one of the notes in the subtree
|
||||||
loadSubtreeNoteIds(childNoteId, subtreeNoteIds);
|
loadSubtreeNoteIds(childNoteId, subtreeNoteIds);
|
||||||
|
|
||||||
function checkTreeCycleInner(parentNoteId) {
|
function checkTreeCycleInner(parentNoteId) {
|
||||||
|
@ -29,6 +29,9 @@ function toBase64(plainText) {
|
|||||||
return Buffer.from(plainText).toString('base64');
|
return Buffer.from(plainText).toString('base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Buffer}
|
||||||
|
*/
|
||||||
function fromBase64(encodedText) {
|
function fromBase64(encodedText) {
|
||||||
return Buffer.from(encodedText, 'base64');
|
return Buffer.from(encodedText, 'base64');
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ async function createMainWindow(app) {
|
|||||||
const windowStateKeeper = require('electron-window-state'); // should not be statically imported
|
const windowStateKeeper = require('electron-window-state'); // should not be statically imported
|
||||||
|
|
||||||
const mainWindowState = windowStateKeeper({
|
const mainWindowState = windowStateKeeper({
|
||||||
// default window width & height so it's usable on 1600 * 900 display (including some extra panels etc.)
|
// default window width & height, so it's usable on 1600 * 900 display (including some extra panels etc.)
|
||||||
defaultWidth: 1200,
|
defaultWidth: 1200,
|
||||||
defaultHeight: 800
|
defaultHeight: 800
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* this is used as a "standalone js" file and required by a shared note directly via script-tags
|
* this is used as a "standalone js" file and required by a shared note directly via script-tags
|
||||||
*
|
*
|
||||||
* data input comes via window variable as follow
|
* data input comes via window variable as follows
|
||||||
* const {elements, appState, files} = window.triliumExcalidraw;
|
* const {elements, appState, files} = window.triliumExcalidraw;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -3,13 +3,12 @@
|
|||||||
* will create 1000 new notes and some clones into a current document.db
|
* will create 1000 new notes and some clones into a current document.db
|
||||||
*/
|
*/
|
||||||
|
|
||||||
require('../entities/entity_constructor');
|
require('../becca/entity_constructor');
|
||||||
const sqlInit = require('../services/sql_init');
|
const sqlInit = require('../services/sql_init');
|
||||||
const noteService = require('../services/notes');
|
const noteService = require('../services/notes');
|
||||||
const attributeService = require('../services/attributes');
|
const attributeService = require('../services/attributes');
|
||||||
const cls = require('../services/cls');
|
const cls = require('../services/cls');
|
||||||
const cloningService = require('../services/cloning');
|
const cloningService = require('../services/cloning');
|
||||||
const noteRevisionService = require('../services/note_revisions');
|
|
||||||
const loremIpsum = require('lorem-ipsum').loremIpsum;
|
const loremIpsum = require('lorem-ipsum').loremIpsum;
|
||||||
|
|
||||||
const noteCount = parseInt(process.argv[2]);
|
const noteCount = parseInt(process.argv[2]);
|
||||||
@ -47,7 +46,7 @@ async function start() {
|
|||||||
format: 'html'
|
format: 'html'
|
||||||
});
|
});
|
||||||
|
|
||||||
const {note} = await noteService.createNewNote({
|
const {note} = noteService.createNewNote({
|
||||||
parentNoteId: getRandomNoteId(),
|
parentNoteId: getRandomNoteId(),
|
||||||
title,
|
title,
|
||||||
content,
|
content,
|
||||||
@ -83,7 +82,7 @@ async function start() {
|
|||||||
isInheritable: Math.random() > 0.1 // 10% are inheritable
|
isInheritable: Math.random() > 0.1 // 10% are inheritable
|
||||||
});
|
});
|
||||||
|
|
||||||
noteRevisionService.createNoteRevision(await becca.getNote(getRandomNoteId()));
|
note.saveNoteRevision();
|
||||||
|
|
||||||
notes.push(note.noteId);
|
notes.push(note.noteId);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user