mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	Compare commits
	
		
			23 Commits
		
	
	
		
			v0.61.5-be
			...
			v0.61.6-be
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 3a83d58b25 | ||
|  | 6fa9d996e8 | ||
|  | 1ea3d238e0 | ||
|  | eb273b7dbb | ||
|  | d2263c68f8 | ||
|  | 97d8b19868 | ||
|  | 2bc7da91a6 | ||
|  | 2b4cbb5f6b | ||
|  | 7b662b04ff | ||
|  | f8e4a665bd | ||
|  | f9a27dd90c | ||
|  | 641985737f | ||
|  | 121e4ba2ea | ||
|  | 01474ecd2d | ||
|  | 82e4e28e7b | ||
|  | 886ee0dbcb | ||
|  | 6f7fbacca1 | ||
|  | 8da5b90aea | ||
|  | e7d57bc08f | ||
|  | 041758766a | ||
|  | f2a510e4c5 | ||
|  | 4717242dc7 | ||
|  | c1865f8564 | 
| @@ -1 +0,0 @@ | |||||||
| module.exports = () => console.log("NOOP, moved to migration 0189"); |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| -- black theme has been removed, dark is closest replacement |  | ||||||
| UPDATE options SET value = 'dark' WHERE name = 'theme' AND value = 'black'; |  | ||||||
|  |  | ||||||
| UPDATE options SET value = 'light' WHERE name = 'theme' AND value = 'white'; |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| ALTER TABLE branches DROP COLUMN utcDateCreated; |  | ||||||
| ALTER TABLE options DROP COLUMN utcDateCreated; |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS "mig_entity_changes" ( |  | ||||||
|                                                 `id`	INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, |  | ||||||
|                                                 `entityName`	TEXT NOT NULL, |  | ||||||
|                                                 `entityId`	TEXT NOT NULL, |  | ||||||
|                                                 `hash`	TEXT NOT NULL, |  | ||||||
|                                                 `isErased` INT NOT NULL, |  | ||||||
|                                                 `changeId` TEXT NOT NULL, |  | ||||||
|                                                 `sourceId` TEXT NOT NULL, |  | ||||||
|                                                 `isSynced` INTEGER NOT NULL, |  | ||||||
|                                                 `utcDateChanged` TEXT NOT NULL |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| INSERT INTO mig_entity_changes (id, entityName, entityId, hash, isErased, changeId, sourceId, isSynced, utcDateChanged) |  | ||||||
|     SELECT id, entityName, entityId, hash, isErased, '', sourceId, isSynced, utcDateChanged FROM entity_changes; |  | ||||||
|  |  | ||||||
| -- delete duplicates https://github.com/zadam/trilium/issues/2534 |  | ||||||
| DELETE FROM mig_entity_changes WHERE isErased = 0 AND id IN ( |  | ||||||
|     SELECT id FROM mig_entity_changes ec |  | ||||||
|     WHERE ( |  | ||||||
|               SELECT COUNT(*) FROM mig_entity_changes |  | ||||||
|               WHERE ec.entityName = mig_entity_changes.entityName |  | ||||||
|                 AND ec.entityId = mig_entity_changes.entityId |  | ||||||
|           ) > 1 |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| DROP TABLE entity_changes; |  | ||||||
|  |  | ||||||
| ALTER TABLE mig_entity_changes RENAME TO entity_changes; |  | ||||||
|  |  | ||||||
| CREATE UNIQUE INDEX `IDX_entityChanges_entityName_entityId` ON "entity_changes" ( |  | ||||||
|                                                                                  `entityName`, |  | ||||||
|                                                                                  `entityId` |  | ||||||
|     ); |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| UPDATE branches SET branchId = 'hidden' where branchId = ( |  | ||||||
|     SELECT branchId FROM branches |  | ||||||
|     WHERE parentNoteId = 'root' |  | ||||||
|       AND noteId = 'hidden' |  | ||||||
|       AND isDeleted = 0 |  | ||||||
|     ORDER BY utcDateModified |  | ||||||
|     LIMIT 1 |  | ||||||
| ); |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| DELETE FROM options WHERE name = 'username'; |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| CREATE TABLE IF NOT EXISTS "etapi_tokens" |  | ||||||
| ( |  | ||||||
|     etapiTokenId TEXT PRIMARY KEY NOT NULL, |  | ||||||
|     name TEXT NOT NULL, |  | ||||||
|     tokenHash TEXT NOT NULL, |  | ||||||
|     utcDateCreated TEXT NOT NULL, |  | ||||||
|     utcDateModified TEXT NOT NULL, |  | ||||||
|     isDeleted INT NOT NULL DEFAULT 0); |  | ||||||
|  |  | ||||||
| INSERT INTO etapi_tokens (etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified, isDeleted) |  | ||||||
| SELECT apiTokenId, 'Trilium Sender', token, utcDateCreated, utcDateCreated, isDeleted FROM api_tokens; |  | ||||||
|  |  | ||||||
| DROP TABLE api_tokens; |  | ||||||
|  |  | ||||||
| UPDATE entity_changes SET entityName = 'etapi_tokens' WHERE entityName = 'api_tokens'; |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| module.exports = () => { |  | ||||||
|     const sql = require('../../src/services/sql'); |  | ||||||
|     const crypto = require('crypto'); |  | ||||||
|  |  | ||||||
|     for (const {etapiTokenId, token} of sql.getRows("SELECT etapiTokenId, tokenHash AS token FROM etapi_tokens")) { |  | ||||||
|         const tokenHash = crypto.createHash('sha256').update(token).digest('base64'); |  | ||||||
|          |  | ||||||
|         sql.execute(`UPDATE etapi_tokens SET tokenHash = ? WHERE etapiTokenId = ?`, [tokenHash, etapiTokenId]); |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
| DROP TABLE entity_changes; |  | ||||||
| -- not preserving the data because of https://github.com/zadam/trilium/issues/3447 |  | ||||||
|  |  | ||||||
| CREATE TABLE IF NOT EXISTS "entity_changes" ( |  | ||||||
|                                                     `id`	INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, |  | ||||||
|                                                     `entityName`	TEXT NOT NULL, |  | ||||||
|                                                     `entityId`	TEXT NOT NULL, |  | ||||||
|                                                     `hash`	TEXT NOT NULL, |  | ||||||
|                                                     `isErased` INT NOT NULL, |  | ||||||
|                                                     `changeId` TEXT NOT NULL, |  | ||||||
|                                                     `componentId` TEXT NOT NULL, |  | ||||||
|                                                     `instanceId` TEXT NOT NULL, |  | ||||||
|                                                     `isSynced` INTEGER NOT NULL, |  | ||||||
|                                                     `utcDateChanged` TEXT NOT NULL |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| CREATE UNIQUE INDEX `IDX_entityChanges_entityName_entityId` ON "entity_changes" ( |  | ||||||
|                                                                                  `entityName`, |  | ||||||
|                                                                                  `entityId` |  | ||||||
|     ); |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| CREATE INDEX `IDX_entity_changes_changeId` ON `entity_changes` (`changeId`); |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| const becca = require('../../src/becca/becca'); |  | ||||||
| const beccaLoader = require('../../src/becca/becca_loader'); |  | ||||||
| const cls = require('../../src/services/cls'); |  | ||||||
|  |  | ||||||
| module.exports = () => { |  | ||||||
|     cls.init(() => { |  | ||||||
|         beccaLoader.load(); |  | ||||||
|  |  | ||||||
|         for (const note of Object.values(becca.notes)) { |  | ||||||
|             if (note.hasLabel('calendarRoot')) { |  | ||||||
|                 note.addLabel('excludeFromNoteMap', "", true); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     }); |  | ||||||
| }; |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| -- removing potential remnants of recent notes in entity changes, see https://github.com/zadam/trilium/issues/2842 |  | ||||||
| DELETE FROM entity_changes WHERE entityName = 'recent_notes'; |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| UPDATE attributes SET value = replace(value, 'setLabelValue', 'updateLabelValue') WHERE name = 'action' AND type = 'label'; |  | ||||||
| UPDATE attributes SET value = replace(value, 'setRelationTarget', 'updateRelationTarget') WHERE name = 'action' AND type = 'label'; |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| module.exports = () => console.log("NOOP, increased because of protected notes IV change"); |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| UPDATE branches SET branchId = '_hidden__search' WHERE parentNoteId = 'hidden' AND noteId = 'search' AND isDeleted = 0; |  | ||||||
| UPDATE branches SET branchId = 'root__globalNoteMap' WHERE parentNoteId = 'singles' AND noteId = 'globalnotemap' AND isDeleted = 0; |  | ||||||
| UPDATE branches SET branchId = '_hidden__sqlConsole' WHERE parentNoteId = 'hidden' AND noteId = 'sqlconsole' AND isDeleted = 0; |  | ||||||
| UPDATE branches SET branchId = 'root__hidden' WHERE parentNoteId = 'root' AND noteId = 'hidden' AND isDeleted = 0; |  | ||||||
| UPDATE branches SET branchId = '_hidden__bulkAction' WHERE parentNoteId = 'hidden' AND noteId = 'bulkaction' AND isDeleted = 0; |  | ||||||
| UPDATE branches SET branchId = '_hidden__share' WHERE parentNoteId = 'root' AND noteId = 'share' AND isDeleted = 0; |  | ||||||
| @@ -1,53 +0,0 @@ | |||||||
| UPDATE notes SET noteId = '_globalNoteMap', title = 'Note Map' WHERE noteId = 'globalnotemap'; |  | ||||||
| UPDATE note_contents SET noteId = '_globalNoteMap' WHERE noteId = 'globalnotemap'; |  | ||||||
| UPDATE note_revisions SET noteId = '_globalNoteMap' WHERE noteId = 'globalnotemap'; |  | ||||||
| UPDATE branches SET noteId = '_globalNoteMap' WHERE noteId = 'globalnotemap'; |  | ||||||
| UPDATE branches SET parentNoteId = '_globalNoteMap' WHERE parentNoteId = 'globalnotemap'; |  | ||||||
| UPDATE attributes SET noteId = '_globalNoteMap' WHERE noteId = 'globalnotemap'; |  | ||||||
| UPDATE attributes SET value = '_globalNoteMap' WHERE type = 'relation' AND value = 'globalnotemap'; |  | ||||||
| UPDATE entity_changes SET entityId = '_globalNoteMap' WHERE entityId = 'globalnotemap'; |  | ||||||
|  |  | ||||||
| UPDATE notes SET noteId = '_bulkAction', title = 'Bulk Action' WHERE noteId = 'bulkaction'; |  | ||||||
| UPDATE note_contents SET noteId = '_bulkAction' WHERE noteId = 'bulkaction'; |  | ||||||
| UPDATE note_revisions SET noteId = '_bulkAction' WHERE noteId = 'bulkaction'; |  | ||||||
| UPDATE branches SET parentNoteId = '_bulkAction' WHERE parentNoteId = 'bulkaction'; |  | ||||||
| UPDATE branches SET noteId = '_bulkAction' WHERE noteId = 'bulkaction'; |  | ||||||
| UPDATE attributes SET noteId = '_bulkAction' WHERE noteId = 'bulkaction'; |  | ||||||
| UPDATE attributes SET value = '_bulkAction' WHERE type = 'relation' AND value = 'bulkaction'; |  | ||||||
| UPDATE entity_changes SET entityId = '_bulkAction' WHERE entityId = 'bulkaction'; |  | ||||||
|  |  | ||||||
| UPDATE notes SET noteId = '_sqlConsole', title = 'SQL Console History' WHERE noteId = 'sqlconsole'; |  | ||||||
| UPDATE note_contents SET noteId = '_sqlConsole' WHERE noteId = 'sqlconsole'; |  | ||||||
| UPDATE note_revisions SET noteId = '_sqlConsole' WHERE noteId = 'sqlconsole'; |  | ||||||
| UPDATE branches SET noteId = '_sqlConsole' WHERE noteId = 'sqlconsole'; |  | ||||||
| UPDATE branches SET parentNoteId = '_sqlConsole' WHERE parentNoteId = 'sqlconsole'; |  | ||||||
| UPDATE attributes SET noteId = '_sqlConsole' WHERE noteId = 'sqlconsole'; |  | ||||||
| UPDATE attributes SET value = '_sqlConsole' WHERE type = 'relation' AND value = 'sqlconsole'; |  | ||||||
| UPDATE entity_changes SET entityId = '_sqlConsole' WHERE entityId = 'sqlconsole'; |  | ||||||
|  |  | ||||||
| UPDATE notes SET noteId = '_hidden', title = 'Hidden Notes' WHERE noteId = 'hidden'; |  | ||||||
| UPDATE note_contents SET noteId = '_hidden' WHERE noteId = 'hidden'; |  | ||||||
| UPDATE note_revisions SET noteId = '_hidden' WHERE noteId = 'hidden'; |  | ||||||
| UPDATE branches SET noteId = '_hidden', prefix = NULL WHERE noteId = 'hidden'; |  | ||||||
| UPDATE branches SET parentNoteId = '_hidden' WHERE parentNoteId = 'hidden'; |  | ||||||
| UPDATE attributes SET noteId = '_hidden' WHERE noteId = 'hidden'; |  | ||||||
| UPDATE attributes SET value = '_hidden' WHERE type = 'relation' AND value = 'hidden'; |  | ||||||
| UPDATE entity_changes SET entityId = '_hidden' WHERE entityId = 'hidden'; |  | ||||||
|  |  | ||||||
| UPDATE notes SET noteId = '_search', title = 'Search History' WHERE noteId = 'search'; |  | ||||||
| UPDATE note_contents SET noteId = '_search' WHERE noteId = 'search'; |  | ||||||
| UPDATE note_revisions SET noteId = '_search' WHERE noteId = 'search'; |  | ||||||
| UPDATE branches SET noteId = '_search' WHERE noteId = 'search'; |  | ||||||
| UPDATE branches SET parentNoteId = '_search' WHERE parentNoteId = 'search'; |  | ||||||
| UPDATE attributes SET noteId = '_search' WHERE noteId = 'search'; |  | ||||||
| UPDATE attributes SET value = '_search' WHERE type = 'relation' AND value = 'search'; |  | ||||||
| UPDATE entity_changes SET entityId = '_search' WHERE entityId = 'search'; |  | ||||||
|  |  | ||||||
| UPDATE notes SET noteId = '_share', title = 'Shared Notes' WHERE noteId = 'share'; |  | ||||||
| UPDATE note_contents SET noteId = '_share' WHERE noteId = 'share'; |  | ||||||
| UPDATE note_revisions SET noteId = '_share' WHERE noteId = 'share'; |  | ||||||
| UPDATE branches SET noteId = '_share' WHERE noteId = 'share'; |  | ||||||
| UPDATE branches SET parentNoteId = '_share' WHERE parentNoteId = 'share'; |  | ||||||
| UPDATE attributes SET noteId = '_share' WHERE noteId = 'share'; |  | ||||||
| UPDATE attributes SET value = '_share' WHERE type = 'relation' AND value = 'share'; |  | ||||||
| UPDATE entity_changes SET entityId = '_share' WHERE entityId = 'share'; |  | ||||||
| @@ -1,12 +0,0 @@ | |||||||
| module.exports = () => { |  | ||||||
|     const hiddenSubtreeService = require('../../src/services/hidden_subtree'); |  | ||||||
|     const cls = require("../../src/services/cls"); |  | ||||||
|     const beccaLoader = require("../../src/becca/becca_loader"); |  | ||||||
|  |  | ||||||
|     cls.init(() => { |  | ||||||
|         beccaLoader.load(); |  | ||||||
|         // make sure the hidden subtree exists since the subsequent migrations we will move some existing notes into it (share...) |  | ||||||
|         // in previous releases hidden subtree was created lazily |  | ||||||
|         hiddenSubtreeService.checkHiddenSubtree(true); |  | ||||||
|     }); |  | ||||||
| }; |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| DELETE FROM branches WHERE noteId = '_share' AND parentNoteId != 'root' AND parentNoteId != '_hidden'; -- delete all other branches of _share if any |  | ||||||
| UPDATE branches SET parentNoteId = '_hidden' WHERE noteId = '_share'; |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| DELETE FROM branches WHERE noteId = '_globalNoteMap' AND parentNoteId != 'singles' AND parentNoteId != '_hidden'; -- make sure there are no clones which would fail at the next line |  | ||||||
| UPDATE branches SET parentNoteId = '_hidden' WHERE noteId = '_globalNoteMap'; |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| DELETE FROM branches WHERE noteId = 'singles'; |  | ||||||
| DELETE FROM notes WHERE noteId = 'singles'; |  | ||||||
| DELETE FROM note_contents WHERE noteId = 'singles'; |  | ||||||
| DELETE FROM note_revisions WHERE noteId = 'singles'; |  | ||||||
| DELETE FROM attributes WHERE noteId = 'singles'; |  | ||||||
| DELETE FROM entity_changes WHERE entityId = 'singles'; |  | ||||||
| @@ -1,21 +0,0 @@ | |||||||
| module.exports = () => { |  | ||||||
|     const cls = require("../../src/services/cls"); |  | ||||||
|     const cloningService = require("../../src/services/cloning"); |  | ||||||
|     const beccaLoader = require("../../src/becca/becca_loader"); |  | ||||||
|     const becca = require("../../src/becca/becca"); |  | ||||||
|  |  | ||||||
|     cls.init(() => { |  | ||||||
|         beccaLoader.load(); |  | ||||||
|  |  | ||||||
|         for (const attr of becca.findAttributes('label','bookmarked')) { |  | ||||||
|             cloningService.toggleNoteInParent(true, attr.noteId, '_lbBookmarks'); |  | ||||||
|  |  | ||||||
|             attr.markAsDeleted("0204__migrate_bookmarks_to_clones"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // bookmarkFolder used to work in 0.57 without the bookmarked label |  | ||||||
|         for (const attr of becca.findAttributes('label','bookmarkFolder')) { |  | ||||||
|             cloningService.toggleNoteInParent(true, attr.noteId, '_lbBookmarks'); |  | ||||||
|         } |  | ||||||
|     }); |  | ||||||
| }; |  | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| UPDATE notes SET type = 'relationMap' WHERE type = 'relation-map'; |  | ||||||
| UPDATE notes SET type = 'noteMap' WHERE type = 'note-map'; |  | ||||||
| UPDATE notes SET type = 'webView' WHERE type = 'web-view'; |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| // the history was previously not exposed and the fact they were not cleaned up is rather a side-effect than an intention |  | ||||||
|  |  | ||||||
| module.exports = () => { |  | ||||||
|     const cls = require("../../src/services/cls"); |  | ||||||
|     const beccaLoader = require("../../src/becca/becca_loader"); |  | ||||||
|     const becca = require("../../src/becca/becca"); |  | ||||||
|  |  | ||||||
|     cls.init(() => { |  | ||||||
|         beccaLoader.load(); |  | ||||||
|  |  | ||||||
|         // deleting just branches because they might be cloned (and therefore saved) also outside of the hidden subtree |  | ||||||
|  |  | ||||||
|         const searchRoot = becca.getNote('_search'); |  | ||||||
|  |  | ||||||
|         for (const searchBranch of searchRoot.getChildBranches()) { |  | ||||||
|             const searchNote = searchBranch.getNote(); |  | ||||||
|  |  | ||||||
|             if (searchNote.type === 'search') { |  | ||||||
|                 searchBranch.deleteBranch('0206__delete_search_and_sql_console_history'); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         const sqlConsoleRoot = becca.getNote('_sqlConsole'); |  | ||||||
|  |  | ||||||
|         for (const sqlConsoleBranch of sqlConsoleRoot.getChildBranches()) { |  | ||||||
|             const sqlConsoleNote = sqlConsoleBranch.getNote(); |  | ||||||
|  |  | ||||||
|             if (sqlConsoleNote.type === 'code' && sqlConsoleNote.mime === 'text/x-sqlite;schema=trilium') { |  | ||||||
|                 sqlConsoleBranch.deleteBranch('0206__delete_search_and_sql_console_history'); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     }); |  | ||||||
| }; |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| UPDATE notes SET title = 'SQL Console History' WHERE noteId = '_sqlConsole'; |  | ||||||
| UPDATE notes SET title = 'Search History' WHERE noteId = '_search'; |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| module.exports = () => { |  | ||||||
|     const cls = require("../../src/services/cls"); |  | ||||||
|     const beccaLoader = require("../../src/becca/becca_loader"); |  | ||||||
|     const becca = require("../../src/becca/becca"); |  | ||||||
|  |  | ||||||
|     cls.init(() => { |  | ||||||
|         beccaLoader.load(); |  | ||||||
|  |  | ||||||
|         for (const label of becca.getNote('_hidden').getLabels('archived')) { |  | ||||||
|             label.markAsDeleted('0208__remove_archived_from_hidden'); |  | ||||||
|         } |  | ||||||
|     }); |  | ||||||
| }; |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| UPDATE attributes SET name = 'workspaceInbox' WHERE type = 'label' AND name = 'hoistedInbox'; |  | ||||||
| UPDATE entity_changes SET entityId = 'workspaceInbox' WHERE entityName = 'attributes' AND entityId = 'hoistedInbox'; |  | ||||||
|  |  | ||||||
| UPDATE attributes SET name = 'workspaceSearchHome' WHERE type = 'label' AND name = 'hoistedSearchHome'; |  | ||||||
| UPDATE entity_changes SET entityId = 'workspaceSearchHome' WHERE entityName = 'attributes' AND entityId = 'hoistedSearchHome'; |  | ||||||
| @@ -1,24 +0,0 @@ | |||||||
| module.exports = async () => { |  | ||||||
|     const cls = require("../../src/services/cls"); |  | ||||||
|     const beccaLoader = require("../../src/becca/becca_loader"); |  | ||||||
|     const log = require("../../src/services/log"); |  | ||||||
|     const consistencyChecks = require("../../src/services/consistency_checks"); |  | ||||||
|     const eraseService = require("../../src/services/erase"); |  | ||||||
|  |  | ||||||
|     await cls.init(async () => { |  | ||||||
|         // precaution for the 0211 migration |  | ||||||
|         eraseService.eraseDeletedNotesNow(); |  | ||||||
|  |  | ||||||
|         beccaLoader.load(); |  | ||||||
|  |  | ||||||
|         try { |  | ||||||
|             // precaution before running 211 which might produce unique constraint problems if the DB was not consistent |  | ||||||
|             consistencyChecks.runOnDemandChecksWithoutExclusiveLock(true); |  | ||||||
|         } |  | ||||||
|         catch (e) { |  | ||||||
|             // consistency checks might start failing in the future if there's some incompatible migration down the road |  | ||||||
|             // we can optimistically assume the DB is consistent and still continue |  | ||||||
|             log.error(`Consistency checks failed in migration 0210: ${e.message} ${e.stack}`); |  | ||||||
|         } |  | ||||||
|     }); |  | ||||||
| }; |  | ||||||
| @@ -1,12 +0,0 @@ | |||||||
| -- case based on isDeleted is needed, otherwise 2 branches (1 deleted, 1 not) might get the same ID |  | ||||||
| UPDATE entity_changes SET entityId = COALESCE(( |  | ||||||
|     SELECT |  | ||||||
|         CASE isDeleted |  | ||||||
|             WHEN 0 THEN parentNoteId || '_' || noteId |  | ||||||
|             WHEN 1 THEN branchId |  | ||||||
|         END |  | ||||||
|     FROM branches WHERE branchId = entityId |  | ||||||
| ), entityId) |  | ||||||
| WHERE entityName = 'branches' AND isErased = 0; |  | ||||||
|  |  | ||||||
| UPDATE branches SET branchId = parentNoteId || '_' || noteId WHERE isDeleted = 0; |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| module.exports = () => { |  | ||||||
|     const cls = require("../../src/services/cls"); |  | ||||||
|     const beccaLoader = require("../../src/becca/becca_loader"); |  | ||||||
|     const becca = require("../../src/becca/becca"); |  | ||||||
|     const log = require("../../src/services/log"); |  | ||||||
|  |  | ||||||
|     cls.init(() => { |  | ||||||
|         beccaLoader.load(); |  | ||||||
|  |  | ||||||
|         const hidden = becca.getNote("_hidden"); |  | ||||||
|  |  | ||||||
|         if (!hidden) { |  | ||||||
|             log.info("MIGRATION 212: no _hidden note, skipping."); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for (const noteId of hidden.getSubtreeNoteIds({includeHidden: true})) { |  | ||||||
|             if (noteId.startsWith("_")) { // is "named" note |  | ||||||
|                 const note = becca.getNote(noteId); |  | ||||||
|  |  | ||||||
|                 for (const attr of note.getOwnedAttributes().slice()) { |  | ||||||
|                     attr.markAsDeleted("0212__delete_all_attributes_of_named_notes"); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     }); |  | ||||||
| }; |  | ||||||
| @@ -1,48 +0,0 @@ | |||||||
| module.exports = () => { |  | ||||||
|     const beccaLoader = require("../../src/becca/becca_loader"); |  | ||||||
|     const becca = require("../../src/becca/becca"); |  | ||||||
|     const cls = require("../../src/services/cls"); |  | ||||||
|     const log = require("../../src/services/log"); |  | ||||||
|  |  | ||||||
|     cls.init(() => { |  | ||||||
|         beccaLoader.load(); |  | ||||||
|  |  | ||||||
|         for (const note of Object.values(becca.notes)) { |  | ||||||
|             try { |  | ||||||
|                 if (!note.isJavaScript()) { |  | ||||||
|                     continue; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if (!note.mime?.endsWith('env=frontend') && !note.mime?.endsWith('env=backend')) { |  | ||||||
|                     continue; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 const origContent = note.getContent().toString(); |  | ||||||
|                 const fixedContent = origContent |  | ||||||
|                     .replaceAll("runOnServer", "runOnBackend") |  | ||||||
|                     .replaceAll("api.refreshTree()", "") |  | ||||||
|                     .replaceAll("addTextToActiveTabEditor", "addTextToActiveContextEditor") |  | ||||||
|                     .replaceAll("getActiveTabNote", "getActiveContextNote") |  | ||||||
|                     .replaceAll("getActiveTabTextEditor", "getActiveContextTextEditor") |  | ||||||
|                     .replaceAll("getActiveTabNotePath", "getActiveContextNotePath") |  | ||||||
|                     .replaceAll("getDateNote", "getDayNote") |  | ||||||
|                     .replaceAll("utils.unescapeHtml", "unescapeHtml") |  | ||||||
|                     .replaceAll("sortNotesByTitle", "sortNotes") |  | ||||||
|                     .replaceAll("CollapsibleWidget", "RightPanelWidget") |  | ||||||
|                     .replaceAll("TabAwareWidget", "NoteContextAwareWidget") |  | ||||||
|                     .replaceAll("TabCachingWidget", "NoteContextAwareWidget") |  | ||||||
|                     .replaceAll("NoteContextCachingWidget", "NoteContextAwareWidget"); |  | ||||||
|  |  | ||||||
|                 if (origContent !== fixedContent) { |  | ||||||
|                     log.info(`Replacing legacy API calls for note '${note.noteId}'`); |  | ||||||
|  |  | ||||||
|                     note.saveNoteRevision(); |  | ||||||
|                     note.setContent(fixedContent); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             catch (e) { |  | ||||||
|                 log.error(`Error during migration to 213 for note '${note.noteId}': ${e.message} ${e.stack}`); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     }); |  | ||||||
| }; |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| UPDATE branches SET notePosition = notePosition - 999899999 WHERE parentNoteId = 'root' AND notePosition > 999999999; |  | ||||||
							
								
								
									
										2876
									
								
								docs/backend_api/BAttachment.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2876
									
								
								docs/backend_api/BAttachment.html
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2693
									
								
								docs/backend_api/BRevision.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2693
									
								
								docs/backend_api/BRevision.html
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -240,7 +240,7 @@ available in the JS backend notes. You can use e.g. <code>api.log(api.startNote. | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line537">line 537</a> |         <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line579">line 579</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -6381,6 +6381,191 @@ if some action needs to happen on only one specific instance. | |||||||
|      |      | ||||||
|  |  | ||||||
|      |      | ||||||
|  |     <h4 class="name" id="runOnFrontend"><span class="type-signature"></span>runOnFrontend<span class="signature">(script, params)</span><span class="type-signature"> → {undefined}</span></h4> | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <div class="description"> | ||||||
|  |     Executes given anonymous function on the frontend(s). | ||||||
|  | Internally this serializes the anonymous function into string and sends it to frontend(s) via WebSocket. | ||||||
|  | Note that there can be multiple connected frontend instances (e.g. in different tabs). In such case, all | ||||||
|  | instances execute the given function. | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     <h5>Parameters:</h5> | ||||||
|  |      | ||||||
|  |  | ||||||
|  | <table class="params"> | ||||||
|  |     <thead> | ||||||
|  |     <tr> | ||||||
|  |          | ||||||
|  |         <th>Name</th> | ||||||
|  |          | ||||||
|  |  | ||||||
|  |         <th>Type</th> | ||||||
|  |  | ||||||
|  |          | ||||||
|  |  | ||||||
|  |          | ||||||
|  |  | ||||||
|  |         <th class="last">Description</th> | ||||||
|  |     </tr> | ||||||
|  |     </thead> | ||||||
|  |  | ||||||
|  |     <tbody> | ||||||
|  |      | ||||||
|  |  | ||||||
|  |         <tr> | ||||||
|  |              | ||||||
|  |                 <td class="name"><code>script</code></td> | ||||||
|  |              | ||||||
|  |  | ||||||
|  |             <td class="type"> | ||||||
|  |              | ||||||
|  |                  | ||||||
|  | <span class="param-type">string</span> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |              | ||||||
|  |             </td> | ||||||
|  |  | ||||||
|  |              | ||||||
|  |  | ||||||
|  |              | ||||||
|  |  | ||||||
|  |             <td class="description last">script to be executed on the frontend</td> | ||||||
|  |         </tr> | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |         <tr> | ||||||
|  |              | ||||||
|  |                 <td class="name"><code>params</code></td> | ||||||
|  |              | ||||||
|  |  | ||||||
|  |             <td class="type"> | ||||||
|  |              | ||||||
|  |                  | ||||||
|  | <span class="param-type">Array.<?></span> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |              | ||||||
|  |             </td> | ||||||
|  |  | ||||||
|  |              | ||||||
|  |  | ||||||
|  |              | ||||||
|  |  | ||||||
|  |             <td class="description last">list of parameters to the anonymous function to be sent to frontend</td> | ||||||
|  |         </tr> | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     </tbody> | ||||||
|  | </table> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <dl class="details"> | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     <dt class="tag-source">Source:</dt> | ||||||
|  |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|  |         <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line543">line 543</a> | ||||||
|  |     </li></ul></dd> | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|  | </dl> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <h5>Returns:</h5> | ||||||
|  |  | ||||||
|  |          | ||||||
|  | <div class="param-desc"> | ||||||
|  |     - no return value is provided. | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <dl> | ||||||
|  |     <dt> | ||||||
|  |         Type | ||||||
|  |     </dt> | ||||||
|  |     <dd> | ||||||
|  |          | ||||||
|  | <span class="param-type">undefined</span> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     </dd> | ||||||
|  | </dl> | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |          | ||||||
|  |              | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |      | ||||||
|     <h4 class="name" id="searchForNote"><span class="type-signature"></span>searchForNote<span class="signature">(query, searchParams<span class="signature-attributes">opt</span>)</span><span class="type-signature"> → {<a href="BNote.html">BNote</a>|null}</span></h4> |     <h4 class="name" id="searchForNote"><span class="type-signature"></span>searchForNote<span class="signature">(query, searchParams<span class="signature-attributes">opt</span>)</span><span class="type-signature"> → {<a href="BNote.html">BNote</a>|null}</span></h4> | ||||||
|      |      | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										284
									
								
								docs/backend_api/becca_entities_battachment.js.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								docs/backend_api/becca_entities_battachment.js.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,284 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="utf-8"> | ||||||
|  |     <title>JSDoc: Source: becca/entities/battachment.js</title> | ||||||
|  |  | ||||||
|  |     <script src="scripts/prettify/prettify.js"> </script> | ||||||
|  |     <script src="scripts/prettify/lang-css.js"> </script> | ||||||
|  |     <!--[if lt IE 9]> | ||||||
|  |       <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> | ||||||
|  |     <![endif]--> | ||||||
|  |     <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> | ||||||
|  |     <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> | ||||||
|  | </head> | ||||||
|  |  | ||||||
|  | <body> | ||||||
|  |  | ||||||
|  | <div id="main"> | ||||||
|  |  | ||||||
|  |     <h1 class="page-title">Source: becca/entities/battachment.js</h1> | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     <section> | ||||||
|  |         <article> | ||||||
|  |             <pre class="prettyprint source linenums"><code>"use strict"; | ||||||
|  |  | ||||||
|  | const utils = require('../../services/utils'); | ||||||
|  | const dateUtils = require('../../services/date_utils'); | ||||||
|  | const AbstractBeccaEntity = require("./abstract_becca_entity"); | ||||||
|  | const sql = require("../../services/sql"); | ||||||
|  | const protectedSessionService = require("../../services/protected_session"); | ||||||
|  | const log = require("../../services/log"); | ||||||
|  |  | ||||||
|  | const attachmentRoleToNoteTypeMapping = { | ||||||
|  |     'image': 'image' | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Attachment represent data related/attached to the note. Conceptually similar to attributes, but intended for | ||||||
|  |  * larger amounts of data and generally not accessible to the user. | ||||||
|  |  * | ||||||
|  |  * @extends AbstractBeccaEntity | ||||||
|  |  */ | ||||||
|  | class BAttachment extends AbstractBeccaEntity { | ||||||
|  |     static get entityName() { return "attachments"; } | ||||||
|  |     static get primaryKeyName() { return "attachmentId"; } | ||||||
|  |     static get hashedProperties() { return ["attachmentId", "ownerId", "role", "mime", "title", "blobId", | ||||||
|  |                                             "utcDateScheduledForErasureSince", "utcDateModified"]; } | ||||||
|  |  | ||||||
|  |     constructor(row) { | ||||||
|  |         super(); | ||||||
|  |  | ||||||
|  |         if (!row.ownerId?.trim()) { | ||||||
|  |             throw new Error("'ownerId' must be given to initialize a Attachment entity"); | ||||||
|  |         } else if (!row.role?.trim()) { | ||||||
|  |             throw new Error("'role' must be given to initialize a Attachment entity"); | ||||||
|  |         } else if (!row.mime?.trim()) { | ||||||
|  |             throw new Error("'mime' must be given to initialize a Attachment entity"); | ||||||
|  |         } else if (!row.title?.trim()) { | ||||||
|  |             throw new Error("'title' must be given to initialize a Attachment entity"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.attachmentId = row.attachmentId; | ||||||
|  |         /** @type {string} either noteId or revisionId to which this attachment belongs */ | ||||||
|  |         this.ownerId = row.ownerId; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.role = row.role; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.mime = row.mime; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.title = row.title; | ||||||
|  |         /** @type {int} */ | ||||||
|  |         this.position = row.position; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.blobId = row.blobId; | ||||||
|  |         /** @type {boolean} */ | ||||||
|  |         this.isProtected = !!row.isProtected; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.dateModified = row.dateModified; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.utcDateModified = row.utcDateModified; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince; | ||||||
|  |  | ||||||
|  |         /** @type {int} optionally added to the entity */ | ||||||
|  |         this.contentLength = row.contentLength; | ||||||
|  |  | ||||||
|  |         this.decrypt(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @returns {BAttachment} */ | ||||||
|  |     copy() { | ||||||
|  |         return new BAttachment({ | ||||||
|  |             ownerId: this.ownerId, | ||||||
|  |             role: this.role, | ||||||
|  |             mime: this.mime, | ||||||
|  |             title: this.title, | ||||||
|  |             blobId: this.blobId, | ||||||
|  |             isProtected: this.isProtected | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @returns {BNote} */ | ||||||
|  |     getNote() { | ||||||
|  |         return this.becca.notes[this.ownerId]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @returns {boolean} true if the note has string content (not binary) */ | ||||||
|  |     hasStringContent() { | ||||||
|  |         return utils.isStringNote(this.type, this.mime); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     isContentAvailable() { | ||||||
|  |         return !this.attachmentId // new attachment which was not encrypted yet | ||||||
|  |             || !this.isProtected | ||||||
|  |             || protectedSessionService.isProtectedSessionAvailable() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getTitleOrProtected() { | ||||||
|  |         return this.isContentAvailable() ? this.title : '[protected]'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     decrypt() { | ||||||
|  |         if (this.isProtected && !this.isDecrypted && protectedSessionService.isProtectedSessionAvailable()) { | ||||||
|  |             try { | ||||||
|  |                 this.title = protectedSessionService.decryptString(this.title); | ||||||
|  |                 this.isDecrypted = true; | ||||||
|  |             } | ||||||
|  |             catch (e) { | ||||||
|  |                 log.error(`Could not decrypt attachment ${this.attachmentId}: ${e.message} ${e.stack}`); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @returns {string|Buffer}  */ | ||||||
|  |     getContent() { | ||||||
|  |         return this._getContent(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param content | ||||||
|  |      * @param {object} [opts] | ||||||
|  |      * @param {object} [opts.forceSave=false] - will also save this BAttachment entity | ||||||
|  |      * @param {object} [opts.forceFrontendReload=false] - override frontend heuristics on when to reload, instruct to reload | ||||||
|  |      */ | ||||||
|  |     setContent(content, opts) { | ||||||
|  |         this._setContent(content, opts); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @returns {{note: BNote, branch: BBranch}} */ | ||||||
|  |     convertToNote() { | ||||||
|  |         if (this.type === 'search') { | ||||||
|  |             throw new Error(`Note of type search cannot have child notes`); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!this.getNote()) { | ||||||
|  |             throw new Error("Cannot find note of this attachment. It is possible that this is note revision's attachment. " + | ||||||
|  |                 "Converting note revision's attachments to note is not (yet) supported."); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!(this.role in attachmentRoleToNoteTypeMapping)) { | ||||||
|  |             throw new Error(`Mapping from attachment role '${this.role}' to note's type is not defined`); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!this.isContentAvailable()) { // isProtected is the same for attachment | ||||||
|  |             throw new Error(`Cannot convert protected attachment outside of protected session`); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const noteService = require('../../services/notes'); | ||||||
|  |  | ||||||
|  |         const { note, branch } = noteService.createNewNote({ | ||||||
|  |             parentNoteId: this.ownerId, | ||||||
|  |             title: this.title, | ||||||
|  |             type: attachmentRoleToNoteTypeMapping[this.role], | ||||||
|  |             mime: this.mime, | ||||||
|  |             content: this.getContent(), | ||||||
|  |             isProtected: this.isProtected | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         this.markAsDeleted(); | ||||||
|  |  | ||||||
|  |         const parentNote = this.getNote(); | ||||||
|  |  | ||||||
|  |         if (this.role === 'image' && parentNote.type === 'text') { | ||||||
|  |             const origContent = parentNote.getContent(); | ||||||
|  |             const oldAttachmentUrl = `api/attachments/${this.attachmentId}/image/`; | ||||||
|  |             const newNoteUrl = `api/images/${note.noteId}/`; | ||||||
|  |  | ||||||
|  |             const fixedContent = utils.replaceAll(origContent, oldAttachmentUrl, newNoteUrl); | ||||||
|  |  | ||||||
|  |             if (fixedContent !== origContent) { | ||||||
|  |                 parentNote.setContent(fixedContent); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             noteService.asyncPostProcessContent(note, fixedContent); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return { note, branch }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getFileName() { | ||||||
|  |         const type = this.role === 'image' ? 'image' : 'file'; | ||||||
|  |  | ||||||
|  |         return utils.formatDownloadTitle(this.title, type, this.mime); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     beforeSaving() { | ||||||
|  |         super.beforeSaving(); | ||||||
|  |  | ||||||
|  |         if (this.position === undefined || this.position === null) { | ||||||
|  |             this.position = 10 + sql.getValue(`SELECT COALESCE(MAX(position), 0) | ||||||
|  |                                               FROM attachments | ||||||
|  |                                               WHERE ownerId = ?`, [this.noteId]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.dateModified = dateUtils.localNowDateTime(); | ||||||
|  |         this.utcDateModified = dateUtils.utcNowDateTime(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getPojo() { | ||||||
|  |         return { | ||||||
|  |             attachmentId: this.attachmentId, | ||||||
|  |             ownerId: this.ownerId, | ||||||
|  |             role: this.role, | ||||||
|  |             mime: this.mime, | ||||||
|  |             title: this.title, | ||||||
|  |             position: this.position, | ||||||
|  |             blobId: this.blobId, | ||||||
|  |             isProtected: !!this.isProtected, | ||||||
|  |             isDeleted: false, | ||||||
|  |             dateModified: this.dateModified, | ||||||
|  |             utcDateModified: this.utcDateModified, | ||||||
|  |             utcDateScheduledForErasureSince: this.utcDateScheduledForErasureSince, | ||||||
|  |             contentLength: this.contentLength | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getPojoToSave() { | ||||||
|  |         const pojo = this.getPojo(); | ||||||
|  |         delete pojo.contentLength; | ||||||
|  |  | ||||||
|  |         if (pojo.isProtected) { | ||||||
|  |             if (this.isDecrypted) { | ||||||
|  |                 pojo.title = protectedSessionService.encrypt(pojo.title); | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 // updating protected note outside of protected session means we will keep original ciphertexts | ||||||
|  |                 delete pojo.title; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return pojo; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = BAttachment; | ||||||
|  | </code></pre> | ||||||
|  |         </article> | ||||||
|  |     </section> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <nav> | ||||||
|  |     <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractBeccaEntity.html">AbstractBeccaEntity</a></li><li><a href="BAttachment.html">BAttachment</a></li><li><a href="BAttribute.html">BAttribute</a></li><li><a href="BBranch.html">BBranch</a></li><li><a href="BEtapiToken.html">BEtapiToken</a></li><li><a href="BNote.html">BNote</a></li><li><a href="BOption.html">BOption</a></li><li><a href="BRecentNote.html">BRecentNote</a></li><li><a href="BRevision.html">BRevision</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li></ul> | ||||||
|  | </nav> | ||||||
|  |  | ||||||
|  | <br class="clear"> | ||||||
|  |  | ||||||
|  | <footer> | ||||||
|  |     Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> | ||||||
|  | </footer> | ||||||
|  |  | ||||||
|  | <script> prettyPrint(); </script> | ||||||
|  | <script src="scripts/linenumber.js"> </script> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										81
									
								
								docs/backend_api/becca_entities_bblob.js.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								docs/backend_api/becca_entities_bblob.js.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="utf-8"> | ||||||
|  |     <title>JSDoc: Source: becca/entities/bblob.js</title> | ||||||
|  |  | ||||||
|  |     <script src="scripts/prettify/prettify.js"> </script> | ||||||
|  |     <script src="scripts/prettify/lang-css.js"> </script> | ||||||
|  |     <!--[if lt IE 9]> | ||||||
|  |       <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> | ||||||
|  |     <![endif]--> | ||||||
|  |     <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> | ||||||
|  |     <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> | ||||||
|  | </head> | ||||||
|  |  | ||||||
|  | <body> | ||||||
|  |  | ||||||
|  | <div id="main"> | ||||||
|  |  | ||||||
|  |     <h1 class="page-title">Source: becca/entities/bblob.js</h1> | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     <section> | ||||||
|  |         <article> | ||||||
|  |             <pre class="prettyprint source linenums"><code>class BBlob { | ||||||
|  |     static get entityName() { return "blobs"; } | ||||||
|  |     static get primaryKeyName() { return "blobId"; } | ||||||
|  |     static get hashedProperties() { return ["blobId", "content"]; } | ||||||
|  |  | ||||||
|  |     constructor(row) { | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.blobId = row.blobId; | ||||||
|  |         /** @type {string|Buffer} */ | ||||||
|  |         this.content = row.content; | ||||||
|  |         /** @type {int} */ | ||||||
|  |         this.contentLength = row.contentLength; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.dateModified = row.dateModified; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.utcDateModified = row.utcDateModified; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getPojo() { | ||||||
|  |         return { | ||||||
|  |             blobId: this.blobId, | ||||||
|  |             content: this.content, | ||||||
|  |             contentLength: this.contentLength, | ||||||
|  |             dateModified: this.dateModified, | ||||||
|  |             utcDateModified: this.utcDateModified | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = BBlob; | ||||||
|  | </code></pre> | ||||||
|  |         </article> | ||||||
|  |     </section> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <nav> | ||||||
|  |     <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractBeccaEntity.html">AbstractBeccaEntity</a></li><li><a href="BAttachment.html">BAttachment</a></li><li><a href="BAttribute.html">BAttribute</a></li><li><a href="BBranch.html">BBranch</a></li><li><a href="BEtapiToken.html">BEtapiToken</a></li><li><a href="BNote.html">BNote</a></li><li><a href="BOption.html">BOption</a></li><li><a href="BRecentNote.html">BRecentNote</a></li><li><a href="BRevision.html">BRevision</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li></ul> | ||||||
|  | </nav> | ||||||
|  |  | ||||||
|  | <br class="clear"> | ||||||
|  |  | ||||||
|  | <footer> | ||||||
|  |     Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> | ||||||
|  | </footer> | ||||||
|  |  | ||||||
|  | <script> prettyPrint(); </script> | ||||||
|  | <script src="scripts/linenumber.js"> </script> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										203
									
								
								docs/backend_api/becca_entities_brevision.js.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								docs/backend_api/becca_entities_brevision.js.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="utf-8"> | ||||||
|  |     <title>JSDoc: Source: becca/entities/brevision.js</title> | ||||||
|  |  | ||||||
|  |     <script src="scripts/prettify/prettify.js"> </script> | ||||||
|  |     <script src="scripts/prettify/lang-css.js"> </script> | ||||||
|  |     <!--[if lt IE 9]> | ||||||
|  |       <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> | ||||||
|  |     <![endif]--> | ||||||
|  |     <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> | ||||||
|  |     <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> | ||||||
|  | </head> | ||||||
|  |  | ||||||
|  | <body> | ||||||
|  |  | ||||||
|  | <div id="main"> | ||||||
|  |  | ||||||
|  |     <h1 class="page-title">Source: becca/entities/brevision.js</h1> | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     <section> | ||||||
|  |         <article> | ||||||
|  |             <pre class="prettyprint source linenums"><code>"use strict"; | ||||||
|  |  | ||||||
|  | const protectedSessionService = require('../../services/protected_session'); | ||||||
|  | const utils = require('../../services/utils'); | ||||||
|  | const dateUtils = require('../../services/date_utils'); | ||||||
|  | const becca = require('../becca'); | ||||||
|  | const AbstractBeccaEntity = require("./abstract_becca_entity"); | ||||||
|  | const sql = require("../../services/sql"); | ||||||
|  | const BAttachment = require("./battachment"); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Revision represents a snapshot of note's title and content at some point in the past. | ||||||
|  |  * It's used for seamless note versioning. | ||||||
|  |  * | ||||||
|  |  * @extends AbstractBeccaEntity | ||||||
|  |  */ | ||||||
|  | class BRevision extends AbstractBeccaEntity { | ||||||
|  |     static get entityName() { return "revisions"; } | ||||||
|  |     static get primaryKeyName() { return "revisionId"; } | ||||||
|  |     static get hashedProperties() { return ["revisionId", "noteId", "title", "isProtected", "dateLastEdited", "dateCreated", | ||||||
|  |                                             "utcDateLastEdited", "utcDateCreated", "utcDateModified", "blobId"]; } | ||||||
|  |  | ||||||
|  |     constructor(row, titleDecrypted = false) { | ||||||
|  |         super(); | ||||||
|  |  | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.revisionId = row.revisionId; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.noteId = row.noteId; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.type = row.type; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.mime = row.mime; | ||||||
|  |         /** @type {boolean} */ | ||||||
|  |         this.isProtected = !!row.isProtected; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.title = row.title; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.blobId = row.blobId; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.dateLastEdited = row.dateLastEdited; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.dateCreated = row.dateCreated; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.utcDateLastEdited = row.utcDateLastEdited; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.utcDateCreated = row.utcDateCreated; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.utcDateModified = row.utcDateModified; | ||||||
|  |         /** @type {int} */ | ||||||
|  |         this.contentLength = row.contentLength; | ||||||
|  |  | ||||||
|  |         if (this.isProtected && !titleDecrypted) { | ||||||
|  |             this.title = protectedSessionService.isProtectedSessionAvailable() | ||||||
|  |                 ? protectedSessionService.decryptString(this.title) | ||||||
|  |                 : "[protected]"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getNote() { | ||||||
|  |         return becca.notes[this.noteId]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @returns {boolean} true if the note has string content (not binary) */ | ||||||
|  |     hasStringContent() { | ||||||
|  |         return utils.isStringNote(this.type, this.mime); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     isContentAvailable() { | ||||||
|  |         return !this.revisionId // new note which was not encrypted yet | ||||||
|  |             || !this.isProtected | ||||||
|  |             || protectedSessionService.isProtectedSessionAvailable() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * Note revision content has quite special handling - it's not a separate entity, but a lazily loaded | ||||||
|  |      * part of Revision entity with its own sync. The reason behind this hybrid design is that | ||||||
|  |      * 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. | ||||||
|  |      * | ||||||
|  |      * This is the same approach as is used for Note's content. | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     /** @returns {string|Buffer} */ | ||||||
|  |     getContent() { | ||||||
|  |         return this._getContent(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @param content | ||||||
|  |      * @param {object} [opts] | ||||||
|  |      * @param {object} [opts.forceSave=false] - will also save this BRevision entity | ||||||
|  |      */ | ||||||
|  |     setContent(content, opts) { | ||||||
|  |         this._setContent(content, opts); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @returns {BAttachment[]} */ | ||||||
|  |     getAttachments() { | ||||||
|  |         return sql.getRows(` | ||||||
|  |                 SELECT attachments.* | ||||||
|  |                 FROM attachments  | ||||||
|  |                 WHERE ownerId = ?  | ||||||
|  |                   AND isDeleted = 0`, [this.revisionId]) | ||||||
|  |             .map(row => new BAttachment(row)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     beforeSaving() { | ||||||
|  |         super.beforeSaving(); | ||||||
|  |  | ||||||
|  |         this.utcDateModified = dateUtils.utcNowDateTime(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getPojo() { | ||||||
|  |         return { | ||||||
|  |             revisionId: this.revisionId, | ||||||
|  |             noteId: this.noteId, | ||||||
|  |             type: this.type, | ||||||
|  |             mime: this.mime, | ||||||
|  |             isProtected: this.isProtected, | ||||||
|  |             title: this.title, | ||||||
|  |             blobId: this.blobId, | ||||||
|  |             dateLastEdited: this.dateLastEdited, | ||||||
|  |             dateCreated: this.dateCreated, | ||||||
|  |             utcDateLastEdited: this.utcDateLastEdited, | ||||||
|  |             utcDateCreated: this.utcDateCreated, | ||||||
|  |             utcDateModified: this.utcDateModified, | ||||||
|  |             content: this.content, // used when retrieving full note revision to frontend | ||||||
|  |             contentLength: this.contentLength | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     getPojoToSave() { | ||||||
|  |         const pojo = this.getPojo(); | ||||||
|  |         delete pojo.content; // not getting persisted | ||||||
|  |         delete pojo.contentLength; // not getting persisted | ||||||
|  |  | ||||||
|  |         if (pojo.isProtected) { | ||||||
|  |             if (protectedSessionService.isProtectedSessionAvailable()) { | ||||||
|  |                 pojo.title = protectedSessionService.encrypt(this.title); | ||||||
|  |             } | ||||||
|  |             else { | ||||||
|  |                 // updating protected note outside of protected session means we will keep original ciphertexts | ||||||
|  |                 delete pojo.title; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return pojo; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = BRevision; | ||||||
|  | </code></pre> | ||||||
|  |         </article> | ||||||
|  |     </section> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <nav> | ||||||
|  |     <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractBeccaEntity.html">AbstractBeccaEntity</a></li><li><a href="BAttachment.html">BAttachment</a></li><li><a href="BAttribute.html">BAttribute</a></li><li><a href="BBranch.html">BBranch</a></li><li><a href="BEtapiToken.html">BEtapiToken</a></li><li><a href="BNote.html">BNote</a></li><li><a href="BOption.html">BOption</a></li><li><a href="BRecentNote.html">BRecentNote</a></li><li><a href="BRevision.html">BRevision</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li></ul> | ||||||
|  | </nav> | ||||||
|  |  | ||||||
|  | <br class="clear"> | ||||||
|  |  | ||||||
|  | <footer> | ||||||
|  |     Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> | ||||||
|  | </footer> | ||||||
|  |  | ||||||
|  | <script> prettyPrint(); </script> | ||||||
|  | <script src="scripts/linenumber.js"> </script> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
| @@ -557,6 +557,48 @@ function BackendScriptApi(currentNote, apiParams) { | |||||||
|      */ |      */ | ||||||
|     this.exportSubtreeToZipFile = async (noteId, format, zipFilePath) => await exportService.exportToZipFile(noteId, format, zipFilePath); |     this.exportSubtreeToZipFile = async (noteId, format, zipFilePath) => await exportService.exportToZipFile(noteId, format, zipFilePath); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Executes given anonymous function on the frontend(s). | ||||||
|  |      * Internally this serializes the anonymous function into string and sends it to frontend(s) via WebSocket. | ||||||
|  |      * Note that there can be multiple connected frontend instances (e.g. in different tabs). In such case, all | ||||||
|  |      * instances execute the given function. | ||||||
|  |      * | ||||||
|  |      * @method | ||||||
|  |      * @param {string} script - script to be executed on the frontend | ||||||
|  |      * @param {Array.<?>} params - list of parameters to the anonymous function to be sent to frontend | ||||||
|  |      * @returns {undefined} - no return value is provided. | ||||||
|  |      */ | ||||||
|  |     this.runOnFrontend = async (script, params = []) => { | ||||||
|  |         if (typeof script === "function") { | ||||||
|  |             script = script.toString(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         ws.sendMessageToAllClients({ | ||||||
|  |             type: 'execute-script', | ||||||
|  |             script: script, | ||||||
|  |             params: prepareParams(params), | ||||||
|  |             startNoteId: this.startNote.noteId, | ||||||
|  |             currentNoteId: this.currentNote.noteId, | ||||||
|  |             originEntityName: "notes", // currently there's no other entity on the frontend which can trigger event | ||||||
|  |             originEntityId: this.originEntity?.noteId || null | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         function prepareParams(params) { | ||||||
|  |             if (!params) { | ||||||
|  |                 return params; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return params.map(p => { | ||||||
|  |                 if (typeof p === "function") { | ||||||
|  |                     return `!@#Function: ${p.toString()}`; | ||||||
|  |                 } | ||||||
|  |                 else { | ||||||
|  |                     return p; | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * This object contains "at your risk" and "no BC guarantees" objects for advanced use cases. |      * This object contains "at your risk" and "no BC guarantees" objects for advanced use cases. | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -1168,7 +1168,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line354">line 354</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line353">line 353</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -1274,7 +1274,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line241">line 241</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line240">line 240</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -1376,7 +1376,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line232">line 232</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line231">line 231</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -1550,7 +1550,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line617">line 617</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line616">line 616</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -1728,7 +1728,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line639">line 639</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line638">line 638</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -1928,7 +1928,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line288">line 288</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line287">line 287</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2107,7 +2107,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line410">line 410</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line409">line 409</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2286,7 +2286,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line420">line 420</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line419">line 419</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2392,7 +2392,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line864">line 864</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line863">line 863</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2496,7 +2496,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line153">line 153</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line152">line 152</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2600,7 +2600,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line170">line 170</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line169">line 169</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2702,7 +2702,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line180">line 180</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line179">line 179</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2804,7 +2804,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line222">line 222</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line221">line 221</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2906,7 +2906,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line227">line 227</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line226">line 226</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3057,7 +3057,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line693">line 693</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line692">line 692</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3212,7 +3212,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line717">line 717</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line716">line 716</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3379,7 +3379,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line503">line 503</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line502">line 502</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3487,7 +3487,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line859">line 859</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line858">line 858</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3589,7 +3589,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line759">line 759</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line758">line 758</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3763,7 +3763,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line606">line 606</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line605">line 605</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3941,7 +3941,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line628">line 628</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line627">line 627</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -4141,7 +4141,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line275">line 275</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line274">line 274</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -4296,7 +4296,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line687">line 687</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line686">line 686</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -4451,7 +4451,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line711">line 711</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line710">line 710</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -4618,7 +4618,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line495">line 495</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line494">line 494</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -4773,7 +4773,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line699">line 699</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line698">line 698</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -4928,7 +4928,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line723">line 723</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line722">line 722</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -5095,7 +5095,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line569">line 569</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line568">line 568</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -5201,7 +5201,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line145">line 145</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line144">line 144</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -5303,7 +5303,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line160">line 160</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line159">line 159</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -5405,7 +5405,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line188">line 188</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line187">line 187</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -5507,7 +5507,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line193">line 193</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line192">line 192</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -5658,7 +5658,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line705">line 705</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line704">line 704</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -5813,7 +5813,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line735">line 735</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line734">line 734</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -5983,7 +5983,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line745">line 745</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line744">line 744</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -6134,7 +6134,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line729">line 729</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line728">line 728</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -6301,7 +6301,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line577">line 577</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line576">line 576</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -6407,7 +6407,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line908">line 908</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line907">line 907</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -6585,7 +6585,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line376">line 376</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line375">line 375</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -6691,7 +6691,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line849">line 849</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line848">line 848</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -6797,7 +6797,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line839">line 839</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line838">line 838</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -6971,7 +6971,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line586">line 586</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line585">line 585</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -7077,7 +7077,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line175">line 175</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line174">line 174</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -7228,7 +7228,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line655">line 655</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line654">line 654</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -7406,7 +7406,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line597">line 597</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line596">line 596</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -7561,7 +7561,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line649">line 649</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line648">line 648</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -7716,7 +7716,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line675">line 675</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line674">line 674</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -7871,7 +7871,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line681">line 681</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line680">line 680</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -7979,7 +7979,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line832">line 832</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line831">line 831</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -8063,7 +8063,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line429">line 429</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line428">line 428</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -8157,7 +8157,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line903">line 903</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line902">line 902</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -8263,7 +8263,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line895">line 895</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line894">line 894</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -8520,7 +8520,7 @@ | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line661">line 661</a> |         <a href="entities_fnote.js.html">entities/fnote.js</a>, <a href="entities_fnote.js.html#line660">line 660</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
|   | |||||||
| @@ -614,7 +614,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line308">line 308</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line309">line 309</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -1819,7 +1819,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line316">line 316</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line317">line 317</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2027,7 +2027,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line458">line 458</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line459">line 459</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2081,7 +2081,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s | |||||||
|      |      | ||||||
|  |  | ||||||
|      |      | ||||||
|     <h4 class="name" id="createLink"><span class="type-signature"></span>createLink<span class="signature">(notePath, params<span class="signature-attributes">opt</span>)</span><span class="type-signature"></span></h4> |     <h4 class="name" id="createLink"><span class="type-signature"></span>createLink<span class="signature">(notePath, params<span class="signature-attributes">opt</span>)</span><span class="type-signature"> → {jQuery}</span></h4> | ||||||
|      |      | ||||||
|  |  | ||||||
|      |      | ||||||
| @@ -2409,7 +2409,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line305">line 305</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line306">line 306</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2434,6 +2434,28 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <h5>Returns:</h5> | ||||||
|  |  | ||||||
|  |          | ||||||
|  | <div class="param-desc"> | ||||||
|  |     - jQuery element with the link (wrapped in <span>) | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <dl> | ||||||
|  |     <dt> | ||||||
|  |         Type | ||||||
|  |     </dt> | ||||||
|  |     <dd> | ||||||
|  |          | ||||||
|  | <span class="param-type">jQuery</span> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     </dd> | ||||||
|  | </dl> | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -2699,7 +2721,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line502">line 502</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line503">line 503</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2854,7 +2876,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line494">line 494</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line495">line 495</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -2964,7 +2986,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line338">line 338</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line339">line 339</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3070,7 +3092,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line322">line 322</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line323">line 323</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3176,7 +3198,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line353">line 353</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line354">line 354</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3286,7 +3308,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line330">line 330</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line331">line 331</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3397,7 +3419,7 @@ implementation of actual widget type. | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line347">line 347</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line348">line 348</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3552,7 +3574,7 @@ implementation of actual widget type. | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line362">line 362</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line363">line 363</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3707,7 +3729,7 @@ implementation of actual widget type. | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line406">line 406</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line407">line 407</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -3969,7 +3991,7 @@ if some action needs to happen on only one specific instance. | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line424">line 424</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line425">line 425</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -4432,7 +4454,7 @@ otherwise (by e.g. createLink()) | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line397">line 397</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line398">line 398</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -4587,7 +4609,7 @@ otherwise (by e.g. createLink()) | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line415">line 415</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line416">line 416</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -4742,7 +4764,7 @@ otherwise (by e.g. createLink()) | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line433">line 433</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line434">line 434</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -4892,7 +4914,7 @@ otherwise (by e.g. createLink()) | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line513">line 513</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line514">line 514</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -5577,7 +5599,7 @@ otherwise (by e.g. createLink()) | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line377">line 377</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line378">line 378</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -5751,7 +5773,7 @@ otherwise (by e.g. createLink()) | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line387">line 387</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line388">line 388</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -5906,7 +5928,7 @@ otherwise (by e.g. createLink()) | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line487">line 487</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line488">line 488</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -6060,7 +6082,7 @@ otherwise (by e.g. createLink()) | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line478">line 478</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line479">line 479</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -6847,7 +6869,7 @@ Internally this serializes the anonymous function into string and sends it to ba | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line442">line 442</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line443">line 443</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -6998,7 +7020,7 @@ Internally this serializes the anonymous function into string and sends it to ba | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line369">line 369</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line370">line 370</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
| @@ -7702,7 +7724,7 @@ Typical use case is when a new note has been created, we should wait until it is | |||||||
|      |      | ||||||
|     <dt class="tag-source">Source:</dt> |     <dt class="tag-source">Source:</dt> | ||||||
|     <dd class="tag-source"><ul class="dummy"><li> |     <dd class="tag-source"><ul class="dummy"><li> | ||||||
|         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line470">line 470</a> |         <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line471">line 471</a> | ||||||
|     </li></ul></dd> |     </li></ul></dd> | ||||||
|      |      | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										95
									
								
								docs/frontend_api/entities_fattachment.js.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								docs/frontend_api/entities_fattachment.js.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="utf-8"> | ||||||
|  |     <title>JSDoc: Source: entities/fattachment.js</title> | ||||||
|  |  | ||||||
|  |     <script src="scripts/prettify/prettify.js"> </script> | ||||||
|  |     <script src="scripts/prettify/lang-css.js"> </script> | ||||||
|  |     <!--[if lt IE 9]> | ||||||
|  |       <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> | ||||||
|  |     <![endif]--> | ||||||
|  |     <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> | ||||||
|  |     <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> | ||||||
|  | </head> | ||||||
|  |  | ||||||
|  | <body> | ||||||
|  |  | ||||||
|  | <div id="main"> | ||||||
|  |  | ||||||
|  |     <h1 class="page-title">Source: entities/fattachment.js</h1> | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     <section> | ||||||
|  |         <article> | ||||||
|  |             <pre class="prettyprint source linenums"><code>class FAttachment { | ||||||
|  |     constructor(froca, row) { | ||||||
|  |         /** @type {Froca} */ | ||||||
|  |         this.froca = froca; | ||||||
|  |  | ||||||
|  |         this.update(row); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     update(row) { | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.attachmentId = row.attachmentId; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.ownerId = row.ownerId; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.role = row.role; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.mime = row.mime; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.title = row.title; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.dateModified = row.dateModified; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.utcDateModified = row.utcDateModified; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.utcDateScheduledForErasureSince = row.utcDateScheduledForErasureSince; | ||||||
|  |  | ||||||
|  |         /** @type {int} optionally added to the entity */ | ||||||
|  |         this.contentLength = row.contentLength; | ||||||
|  |  | ||||||
|  |         this.froca.attachments[this.attachmentId] = this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @returns {FNote} */ | ||||||
|  |     getNote() { | ||||||
|  |         return this.froca.notes[this.ownerId]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** @return {FBlob} */ | ||||||
|  |     async getBlob() { | ||||||
|  |         return await this.froca.getBlob('attachments', this.attachmentId); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default FAttachment; | ||||||
|  | </code></pre> | ||||||
|  |         </article> | ||||||
|  |     </section> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <nav> | ||||||
|  |     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="FAttribute.html">FAttribute</a></li><li><a href="FBranch.html">FBranch</a></li><li><a href="FNote.html">FNote</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li></ul> | ||||||
|  | </nav> | ||||||
|  |  | ||||||
|  | <br class="clear"> | ||||||
|  |  | ||||||
|  | <footer> | ||||||
|  |     Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> | ||||||
|  | </footer> | ||||||
|  |  | ||||||
|  | <script> prettyPrint(); </script> | ||||||
|  | <script src="scripts/linenumber.js"> </script> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
							
								
								
									
										69
									
								
								docs/frontend_api/entities_fblob.js.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								docs/frontend_api/entities_fblob.js.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="utf-8"> | ||||||
|  |     <title>JSDoc: Source: entities/fblob.js</title> | ||||||
|  |  | ||||||
|  |     <script src="scripts/prettify/prettify.js"> </script> | ||||||
|  |     <script src="scripts/prettify/lang-css.js"> </script> | ||||||
|  |     <!--[if lt IE 9]> | ||||||
|  |       <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> | ||||||
|  |     <![endif]--> | ||||||
|  |     <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> | ||||||
|  |     <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> | ||||||
|  | </head> | ||||||
|  |  | ||||||
|  | <body> | ||||||
|  |  | ||||||
|  | <div id="main"> | ||||||
|  |  | ||||||
|  |     <h1 class="page-title">Source: entities/fblob.js</h1> | ||||||
|  |  | ||||||
|  |      | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     <section> | ||||||
|  |         <article> | ||||||
|  |             <pre class="prettyprint source linenums"><code>export default class FBlob { | ||||||
|  |     constructor(row) { | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.blobId = row.blobId; | ||||||
|  |  | ||||||
|  |         /** | ||||||
|  |          * can either contain the whole content (in e.g. string notes), only part (large text notes) or nothing at all (binary notes, images) | ||||||
|  |          * @type {string} | ||||||
|  |          */ | ||||||
|  |         this.content = row.content; | ||||||
|  |         this.contentLength = row.contentLength; | ||||||
|  |  | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.dateModified = row.dateModified; | ||||||
|  |         /** @type {string} */ | ||||||
|  |         this.utcDateModified = row.utcDateModified; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | </code></pre> | ||||||
|  |         </article> | ||||||
|  |     </section> | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <nav> | ||||||
|  |     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="FAttribute.html">FAttribute</a></li><li><a href="FBranch.html">FBranch</a></li><li><a href="FNote.html">FNote</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li></ul> | ||||||
|  | </nav> | ||||||
|  |  | ||||||
|  | <br class="clear"> | ||||||
|  |  | ||||||
|  | <footer> | ||||||
|  |     Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a> | ||||||
|  | </footer> | ||||||
|  |  | ||||||
|  | <script> prettyPrint(); </script> | ||||||
|  | <script src="scripts/linenumber.js"> </script> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
| @@ -148,10 +148,9 @@ class FNote { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async getContent() { |     async getContent() { | ||||||
|         // we're not caching content since these objects are in froca and as such pretty long-lived |         const blob = await this.getBlob(); | ||||||
|         const note = await server.get(`notes/${this.noteId}`); |  | ||||||
|  |  | ||||||
|         return note.content; |         return blob?.content; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async getJsonContent() { |     async getJsonContent() { | ||||||
|   | |||||||
| @@ -329,6 +329,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain | |||||||
|      * @param {boolean} [params.showNotePath=false] - show also whole note's path as part of the link |      * @param {boolean} [params.showNotePath=false] - show also whole note's path as part of the link | ||||||
|      * @param {boolean} [params.showNoteIcon=false] - show also note icon before the title |      * @param {boolean} [params.showNoteIcon=false] - show also note icon before the title | ||||||
|      * @param {string} [params.title=] - custom link tile with note's title as default |      * @param {string} [params.title=] - custom link tile with note's title as default | ||||||
|  |      * @returns {jQuery} - jQuery element with the link (wrapped in <span>) | ||||||
|      */ |      */ | ||||||
|     this.createLink = linkService.createLink; |     this.createLink = linkService.createLink; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,8 +5,8 @@ | |||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * CKEditor 5 (v39.0.1) content styles. |  * CKEditor 5 (v39.0.2) content styles. | ||||||
|  * Generated on Thu, 10 Aug 2023 09:21:07 GMT. |  * Generated on Wed, 06 Sep 2023 07:32:15 GMT. | ||||||
|  * For more information, check out https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/content-styles.html |  * For more information, check out https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/content-styles.html | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| @@ -197,6 +197,20 @@ | |||||||
| .ck-content .todo-list .todo-list__label .todo-list__label__description { | .ck-content .todo-list .todo-list__label .todo-list__label__description { | ||||||
|     vertical-align: middle; |     vertical-align: middle; | ||||||
| } | } | ||||||
|  | /* @ckeditor/ckeditor5-image/theme/imageresize.css */ | ||||||
|  | .ck-content .image.image_resized { | ||||||
|  |     max-width: 100%; | ||||||
|  |     display: block; | ||||||
|  |     box-sizing: border-box; | ||||||
|  | } | ||||||
|  | /* @ckeditor/ckeditor5-image/theme/imageresize.css */ | ||||||
|  | .ck-content .image.image_resized img { | ||||||
|  |     width: 100%; | ||||||
|  | } | ||||||
|  | /* @ckeditor/ckeditor5-image/theme/imageresize.css */ | ||||||
|  | .ck-content .image.image_resized > figcaption { | ||||||
|  |     display: block; | ||||||
|  | } | ||||||
| /* @ckeditor/ckeditor5-image/theme/image.css */ | /* @ckeditor/ckeditor5-image/theme/image.css */ | ||||||
| .ck-content .image { | .ck-content .image { | ||||||
|     display: table; |     display: table; | ||||||
| @@ -234,20 +248,6 @@ | |||||||
|     flex-shrink: 1; |     flex-shrink: 1; | ||||||
|     max-width: 100%; |     max-width: 100%; | ||||||
| } | } | ||||||
| /* @ckeditor/ckeditor5-image/theme/imageresize.css */ |  | ||||||
| .ck-content .image.image_resized { |  | ||||||
|     max-width: 100%; |  | ||||||
|     display: block; |  | ||||||
|     box-sizing: border-box; |  | ||||||
| } |  | ||||||
| /* @ckeditor/ckeditor5-image/theme/imageresize.css */ |  | ||||||
| .ck-content .image.image_resized img { |  | ||||||
|     width: 100%; |  | ||||||
| } |  | ||||||
| /* @ckeditor/ckeditor5-image/theme/imageresize.css */ |  | ||||||
| .ck-content .image.image_resized > figcaption { |  | ||||||
|     display: block; |  | ||||||
| } |  | ||||||
| /* @ckeditor/ckeditor5-image/theme/imagecaption.css */ | /* @ckeditor/ckeditor5-image/theme/imagecaption.css */ | ||||||
| .ck-content .image > figcaption { | .ck-content .image > figcaption { | ||||||
|     display: table-caption; |     display: table-caption; | ||||||
| @@ -259,32 +259,6 @@ | |||||||
|     font-size: .75em; |     font-size: .75em; | ||||||
|     outline-offset: -1px; |     outline-offset: -1px; | ||||||
| } | } | ||||||
| /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ |  | ||||||
| .ck-content .marker-yellow { |  | ||||||
|     background-color: var(--ck-highlight-marker-yellow); |  | ||||||
| } |  | ||||||
| /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ |  | ||||||
| .ck-content .marker-green { |  | ||||||
|     background-color: var(--ck-highlight-marker-green); |  | ||||||
| } |  | ||||||
| /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ |  | ||||||
| .ck-content .marker-pink { |  | ||||||
|     background-color: var(--ck-highlight-marker-pink); |  | ||||||
| } |  | ||||||
| /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ |  | ||||||
| .ck-content .marker-blue { |  | ||||||
|     background-color: var(--ck-highlight-marker-blue); |  | ||||||
| } |  | ||||||
| /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ |  | ||||||
| .ck-content .pen-red { |  | ||||||
|     color: var(--ck-highlight-pen-red); |  | ||||||
|     background-color: transparent; |  | ||||||
| } |  | ||||||
| /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ |  | ||||||
| .ck-content .pen-green { |  | ||||||
|     color: var(--ck-highlight-pen-green); |  | ||||||
|     background-color: transparent; |  | ||||||
| } |  | ||||||
| /* @ckeditor/ckeditor5-list/theme/list.css */ | /* @ckeditor/ckeditor5-list/theme/list.css */ | ||||||
| .ck-content ol { | .ck-content ol { | ||||||
|     list-style-type: decimal; |     list-style-type: decimal; | ||||||
| @@ -321,6 +295,32 @@ | |||||||
| .ck-content ul ul ul ul { | .ck-content ul ul ul ul { | ||||||
|     list-style-type: square; |     list-style-type: square; | ||||||
| } | } | ||||||
|  | /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ | ||||||
|  | .ck-content .marker-yellow { | ||||||
|  |     background-color: var(--ck-highlight-marker-yellow); | ||||||
|  | } | ||||||
|  | /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ | ||||||
|  | .ck-content .marker-green { | ||||||
|  |     background-color: var(--ck-highlight-marker-green); | ||||||
|  | } | ||||||
|  | /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ | ||||||
|  | .ck-content .marker-pink { | ||||||
|  |     background-color: var(--ck-highlight-marker-pink); | ||||||
|  | } | ||||||
|  | /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ | ||||||
|  | .ck-content .marker-blue { | ||||||
|  |     background-color: var(--ck-highlight-marker-blue); | ||||||
|  | } | ||||||
|  | /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ | ||||||
|  | .ck-content .pen-red { | ||||||
|  |     color: var(--ck-highlight-pen-red); | ||||||
|  |     background-color: transparent; | ||||||
|  | } | ||||||
|  | /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ | ||||||
|  | .ck-content .pen-green { | ||||||
|  |     color: var(--ck-highlight-pen-green); | ||||||
|  |     background-color: transparent; | ||||||
|  | } | ||||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||||
| .ck-content .image-style-block-align-left, | .ck-content .image-style-block-align-left, | ||||||
| .ck-content .image-style-block-align-right { | .ck-content .image-style-block-align-right { | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										901
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										901
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										32
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								package.json
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | |||||||
|   "name": "trilium", |   "name": "trilium", | ||||||
|   "productName": "Trilium Notes", |   "productName": "Trilium Notes", | ||||||
|   "description": "Trilium Notes", |   "description": "Trilium Notes", | ||||||
|   "version": "0.61.5-beta", |   "version": "0.61.6-beta", | ||||||
|   "license": "AGPL-3.0-only", |   "license": "AGPL-3.0-only", | ||||||
|   "main": "electron.js", |   "main": "electron.js", | ||||||
|   "bin": { |   "bin": { | ||||||
| @@ -32,11 +32,11 @@ | |||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@braintree/sanitize-url": "6.0.4", |     "@braintree/sanitize-url": "6.0.4", | ||||||
|     "@electron/remote": "2.0.10", |     "@electron/remote": "2.0.11", | ||||||
|     "@excalidraw/excalidraw": "0.15.3", |     "@excalidraw/excalidraw": "0.15.3", | ||||||
|     "archiver": "5.3.1", |     "archiver": "5.3.1", | ||||||
|     "async-mutex": "0.4.0", |     "async-mutex": "0.4.0", | ||||||
|     "axios": "1.4.0", |     "axios": "1.5.0", | ||||||
|     "better-sqlite3": "8.4.0", |     "better-sqlite3": "8.4.0", | ||||||
|     "chokidar": "3.5.3", |     "chokidar": "3.5.3", | ||||||
|     "cls-hooked": "4.2.2", |     "cls-hooked": "4.2.2", | ||||||
| @@ -53,14 +53,14 @@ | |||||||
|     "escape-html": "1.0.3", |     "escape-html": "1.0.3", | ||||||
|     "express": "4.18.2", |     "express": "4.18.2", | ||||||
|     "express-partial-content": "1.0.2", |     "express-partial-content": "1.0.2", | ||||||
|     "express-rate-limit": "6.9.0", |     "express-rate-limit": "6.11.0", | ||||||
|     "express-session": "1.17.3", |     "express-session": "1.17.3", | ||||||
|     "fs-extra": "11.1.1", |     "fs-extra": "11.1.1", | ||||||
|     "helmet": "7.0.0", |     "helmet": "7.0.0", | ||||||
|     "html": "1.0.0", |     "html": "1.0.0", | ||||||
|     "html2plaintext": "2.1.4", |     "html2plaintext": "2.1.4", | ||||||
|     "http-proxy-agent": "7.0.0", |     "http-proxy-agent": "7.0.0", | ||||||
|     "https-proxy-agent": "7.0.1", |     "https-proxy-agent": "7.0.2", | ||||||
|     "image-type": "4.1.0", |     "image-type": "4.1.0", | ||||||
|     "ini": "3.0.1", |     "ini": "3.0.1", | ||||||
|     "is-animated": "2.0.2", |     "is-animated": "2.0.2", | ||||||
| @@ -68,10 +68,10 @@ | |||||||
|     "jimp": "0.22.10", |     "jimp": "0.22.10", | ||||||
|     "joplin-turndown-plugin-gfm": "1.0.12", |     "joplin-turndown-plugin-gfm": "1.0.12", | ||||||
|     "jsdom": "22.1.0", |     "jsdom": "22.1.0", | ||||||
|     "marked": "7.0.3", |     "marked": "8.0.1", | ||||||
|     "mime-types": "2.1.35", |     "mime-types": "2.1.35", | ||||||
|     "multer": "1.4.5-lts.1", |     "multer": "1.4.5-lts.1", | ||||||
|     "node-abi": "3.46.0", |     "node-abi": "3.47.0", | ||||||
|     "normalize-strings": "1.1.1", |     "normalize-strings": "1.1.1", | ||||||
|     "open": "8.4.1", |     "open": "8.4.1", | ||||||
|     "rand-token": "1.0.1", |     "rand-token": "1.0.1", | ||||||
| @@ -91,20 +91,20 @@ | |||||||
|     "tmp": "0.2.1", |     "tmp": "0.2.1", | ||||||
|     "turndown": "7.1.2", |     "turndown": "7.1.2", | ||||||
|     "unescape": "1.0.1", |     "unescape": "1.0.1", | ||||||
|     "ws": "8.13.0", |     "ws": "8.14.0", | ||||||
|     "xml2js": "0.6.2", |     "xml2js": "0.6.2", | ||||||
|     "yauzl": "2.10.0" |     "yauzl": "2.10.0" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "cross-env": "7.0.3", |     "cross-env": "7.0.3", | ||||||
|     "electron": "25.5.0", |     "electron": "25.8.0", | ||||||
|     "electron-builder": "24.6.3", |     "electron-builder": "24.6.4", | ||||||
|     "electron-packager": "17.1.1", |     "electron-packager": "17.1.2", | ||||||
|     "electron-rebuild": "3.2.9", |     "electron-rebuild": "3.2.9", | ||||||
|     "eslint": "8.47.0", |     "eslint": "8.48.0", | ||||||
|     "eslint-config-airbnb-base": "15.0.0", |     "eslint-config-airbnb-base": "15.0.0", | ||||||
|     "eslint-config-prettier": "9.0.0", |     "eslint-config-prettier": "9.0.0", | ||||||
|     "eslint-plugin-import": "2.28.0", |     "eslint-plugin-import": "2.28.1", | ||||||
|     "eslint-plugin-jsonc": "2.9.0", |     "eslint-plugin-jsonc": "2.9.0", | ||||||
|     "eslint-plugin-prettier": "5.0.0", |     "eslint-plugin-prettier": "5.0.0", | ||||||
|     "esm": "3.2.25", |     "esm": "3.2.25", | ||||||
| @@ -112,16 +112,16 @@ | |||||||
|     "jasmine": "5.1.0", |     "jasmine": "5.1.0", | ||||||
|     "jsdoc": "4.0.2", |     "jsdoc": "4.0.2", | ||||||
|     "jsonc-eslint-parser": "2.3.0", |     "jsonc-eslint-parser": "2.3.0", | ||||||
|     "lint-staged": "14.0.0", |     "lint-staged": "14.0.1", | ||||||
|     "lorem-ipsum": "2.0.8", |     "lorem-ipsum": "2.0.8", | ||||||
|     "nodemon": "3.0.1", |     "nodemon": "3.0.1", | ||||||
|     "prettier": "3.0.2", |     "prettier": "3.0.3", | ||||||
|     "rcedit": "3.1.0", |     "rcedit": "3.1.0", | ||||||
|     "webpack": "5.88.2", |     "webpack": "5.88.2", | ||||||
|     "webpack-cli": "5.1.4" |     "webpack-cli": "5.1.4" | ||||||
|   }, |   }, | ||||||
|   "optionalDependencies": { |   "optionalDependencies": { | ||||||
|     "electron-installer-debian": "3.1.0" |     "electron-installer-debian": "3.2.0" | ||||||
|   }, |   }, | ||||||
|   "lint-staged": { |   "lint-staged": { | ||||||
|     "*.js": "eslint --cache --fix" |     "*.js": "eslint --cache --fix" | ||||||
|   | |||||||
| @@ -4,6 +4,9 @@ describe("Lexer fulltext", () => { | |||||||
|     it("simple lexing", () => { |     it("simple lexing", () => { | ||||||
|         expect(lex("hello world").fulltextTokens.map(t => t.token)) |         expect(lex("hello world").fulltextTokens.map(t => t.token)) | ||||||
|             .toEqual(["hello", "world"]); |             .toEqual(["hello", "world"]); | ||||||
|  |  | ||||||
|  |         expect(lex("hello, world").fulltextTokens.map(t => t.token)) | ||||||
|  |             .toEqual(["hello", "world"]); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it("use quotes to keep words together", () => { |     it("use quotes to keep words together", () => { | ||||||
| @@ -147,6 +150,11 @@ describe("Lexer expression", () => { | |||||||
|         expect(lex(`# not(#capital) and note.noteId != "root"`).expressionTokens.map(t => t.token)) |         expect(lex(`# not(#capital) and note.noteId != "root"`).expressionTokens.map(t => t.token)) | ||||||
|             .toEqual(["#", "not", "(", "#capital", ")", "and", "note", ".", "noteid", "!=", "root"]); |             .toEqual(["#", "not", "(", "#capital", ")", "and", "note", ".", "noteid", "!=", "root"]); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|  |     it("order by multiple labels", () => { | ||||||
|  |         expect(lex(`# orderby #a,#b`).expressionTokens.map(t => t.token)) | ||||||
|  |             .toEqual(["#", "orderby", "#a", ",", "#b"]); | ||||||
|  |     }); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| describe("Lexer invalid queries and edge cases", () => { | describe("Lexer invalid queries and edge cases", () => { | ||||||
|   | |||||||
| @@ -36,9 +36,9 @@ describe("Parser", () => { | |||||||
|  |  | ||||||
|         expect(rootExp.constructor.name).toEqual("AndExp"); |         expect(rootExp.constructor.name).toEqual("AndExp"); | ||||||
|         expect(rootExp.subExpressions[0].constructor.name).toEqual("PropertyComparisonExp"); |         expect(rootExp.subExpressions[0].constructor.name).toEqual("PropertyComparisonExp"); | ||||||
|         expect(rootExp.subExpressions[1].constructor.name).toEqual("OrExp"); |         expect(rootExp.subExpressions[2].constructor.name).toEqual("OrExp"); | ||||||
|         expect(rootExp.subExpressions[1].subExpressions[0].constructor.name).toEqual("NoteFlatTextExp"); |         expect(rootExp.subExpressions[2].subExpressions[0].constructor.name).toEqual("NoteFlatTextExp"); | ||||||
|         expect(rootExp.subExpressions[1].subExpressions[0].tokens).toEqual(["hello", "hi"]); |         expect(rootExp.subExpressions[2].subExpressions[0].tokens).toEqual(["hello", "hi"]); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it("fulltext parser with content", () => { |     it("fulltext parser with content", () => { | ||||||
| @@ -51,9 +51,9 @@ describe("Parser", () => { | |||||||
|         expect(rootExp.constructor.name).toEqual("AndExp"); |         expect(rootExp.constructor.name).toEqual("AndExp"); | ||||||
|         assertIsArchived(rootExp.subExpressions[0]); |         assertIsArchived(rootExp.subExpressions[0]); | ||||||
|  |  | ||||||
|         expect(rootExp.subExpressions[1].constructor.name).toEqual("OrExp"); |         expect(rootExp.subExpressions[2].constructor.name).toEqual("OrExp"); | ||||||
|  |  | ||||||
|         const subs = rootExp.subExpressions[1].subExpressions; |         const subs = rootExp.subExpressions[2].subExpressions; | ||||||
|  |  | ||||||
|         expect(subs[0].constructor.name).toEqual("NoteFlatTextExp"); |         expect(subs[0].constructor.name).toEqual("NoteFlatTextExp"); | ||||||
|         expect(subs[0].tokens).toEqual(["hello", "hi"]); |         expect(subs[0].tokens).toEqual(["hello", "hi"]); | ||||||
| @@ -71,10 +71,10 @@ describe("Parser", () => { | |||||||
|  |  | ||||||
|         expect(rootExp.constructor.name).toEqual("AndExp"); |         expect(rootExp.constructor.name).toEqual("AndExp"); | ||||||
|         assertIsArchived(rootExp.subExpressions[0]); |         assertIsArchived(rootExp.subExpressions[0]); | ||||||
|         expect(rootExp.subExpressions[1].constructor.name).toEqual("LabelComparisonExp"); |         expect(rootExp.subExpressions[2].constructor.name).toEqual("LabelComparisonExp"); | ||||||
|         expect(rootExp.subExpressions[1].attributeType).toEqual("label"); |         expect(rootExp.subExpressions[2].attributeType).toEqual("label"); | ||||||
|         expect(rootExp.subExpressions[1].attributeName).toEqual("mylabel"); |         expect(rootExp.subExpressions[2].attributeName).toEqual("mylabel"); | ||||||
|         expect(rootExp.subExpressions[1].comparator).toBeTruthy(); |         expect(rootExp.subExpressions[2].comparator).toBeTruthy(); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it("simple attribute negation", () => { |     it("simple attribute negation", () => { | ||||||
| @@ -86,10 +86,10 @@ describe("Parser", () => { | |||||||
|  |  | ||||||
|         expect(rootExp.constructor.name).toEqual("AndExp"); |         expect(rootExp.constructor.name).toEqual("AndExp"); | ||||||
|         assertIsArchived(rootExp.subExpressions[0]); |         assertIsArchived(rootExp.subExpressions[0]); | ||||||
|         expect(rootExp.subExpressions[1].constructor.name).toEqual("NotExp"); |         expect(rootExp.subExpressions[2].constructor.name).toEqual("NotExp"); | ||||||
|         expect(rootExp.subExpressions[1].subExpression.constructor.name).toEqual("AttributeExistsExp"); |         expect(rootExp.subExpressions[2].subExpression.constructor.name).toEqual("AttributeExistsExp"); | ||||||
|         expect(rootExp.subExpressions[1].subExpression.attributeType).toEqual("label"); |         expect(rootExp.subExpressions[2].subExpression.attributeType).toEqual("label"); | ||||||
|         expect(rootExp.subExpressions[1].subExpression.attributeName).toEqual("mylabel"); |         expect(rootExp.subExpressions[2].subExpression.attributeName).toEqual("mylabel"); | ||||||
|  |  | ||||||
|         rootExp = parse({ |         rootExp = parse({ | ||||||
|             fulltextTokens: [], |             fulltextTokens: [], | ||||||
| @@ -99,10 +99,10 @@ describe("Parser", () => { | |||||||
|  |  | ||||||
|         expect(rootExp.constructor.name).toEqual("AndExp"); |         expect(rootExp.constructor.name).toEqual("AndExp"); | ||||||
|         assertIsArchived(rootExp.subExpressions[0]); |         assertIsArchived(rootExp.subExpressions[0]); | ||||||
|         expect(rootExp.subExpressions[1].constructor.name).toEqual("NotExp"); |         expect(rootExp.subExpressions[2].constructor.name).toEqual("NotExp"); | ||||||
|         expect(rootExp.subExpressions[1].subExpression.constructor.name).toEqual("AttributeExistsExp"); |         expect(rootExp.subExpressions[2].subExpression.constructor.name).toEqual("AttributeExistsExp"); | ||||||
|         expect(rootExp.subExpressions[1].subExpression.attributeType).toEqual("relation"); |         expect(rootExp.subExpressions[2].subExpression.attributeType).toEqual("relation"); | ||||||
|         expect(rootExp.subExpressions[1].subExpression.attributeName).toEqual("myrelation"); |         expect(rootExp.subExpressions[2].subExpression.attributeName).toEqual("myrelation"); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it("simple label AND", () => { |     it("simple label AND", () => { | ||||||
| @@ -115,8 +115,8 @@ describe("Parser", () => { | |||||||
|         expect(rootExp.constructor.name).toEqual("AndExp"); |         expect(rootExp.constructor.name).toEqual("AndExp"); | ||||||
|         assertIsArchived(rootExp.subExpressions[0]); |         assertIsArchived(rootExp.subExpressions[0]); | ||||||
|  |  | ||||||
|         expect(rootExp.subExpressions[1].constructor.name).toEqual("AndExp"); |         expect(rootExp.subExpressions[2].constructor.name).toEqual("AndExp"); | ||||||
|         const [firstSub, secondSub] = rootExp.subExpressions[1].subExpressions; |         const [firstSub, secondSub] = rootExp.subExpressions[2].subExpressions; | ||||||
|  |  | ||||||
|         expect(firstSub.constructor.name).toEqual("LabelComparisonExp"); |         expect(firstSub.constructor.name).toEqual("LabelComparisonExp"); | ||||||
|         expect(firstSub.attributeName).toEqual("first"); |         expect(firstSub.attributeName).toEqual("first"); | ||||||
| @@ -135,8 +135,8 @@ describe("Parser", () => { | |||||||
|         expect(rootExp.constructor.name).toEqual("AndExp"); |         expect(rootExp.constructor.name).toEqual("AndExp"); | ||||||
|         assertIsArchived(rootExp.subExpressions[0]); |         assertIsArchived(rootExp.subExpressions[0]); | ||||||
|  |  | ||||||
|         expect(rootExp.subExpressions[1].constructor.name).toEqual("AndExp"); |         expect(rootExp.subExpressions[2].constructor.name).toEqual("AndExp"); | ||||||
|         const [firstSub, secondSub] = rootExp.subExpressions[1].subExpressions; |         const [firstSub, secondSub] = rootExp.subExpressions[2].subExpressions; | ||||||
|  |  | ||||||
|         expect(firstSub.constructor.name).toEqual("LabelComparisonExp"); |         expect(firstSub.constructor.name).toEqual("LabelComparisonExp"); | ||||||
|         expect(firstSub.attributeName).toEqual("first"); |         expect(firstSub.attributeName).toEqual("first"); | ||||||
| @@ -155,8 +155,8 @@ describe("Parser", () => { | |||||||
|         expect(rootExp.constructor.name).toEqual("AndExp"); |         expect(rootExp.constructor.name).toEqual("AndExp"); | ||||||
|         assertIsArchived(rootExp.subExpressions[0]); |         assertIsArchived(rootExp.subExpressions[0]); | ||||||
|  |  | ||||||
|         expect(rootExp.subExpressions[1].constructor.name).toEqual("OrExp"); |         expect(rootExp.subExpressions[2].constructor.name).toEqual("OrExp"); | ||||||
|         const [firstSub, secondSub] = rootExp.subExpressions[1].subExpressions; |         const [firstSub, secondSub] = rootExp.subExpressions[2].subExpressions; | ||||||
|  |  | ||||||
|         expect(firstSub.constructor.name).toEqual("LabelComparisonExp"); |         expect(firstSub.constructor.name).toEqual("LabelComparisonExp"); | ||||||
|         expect(firstSub.attributeName).toEqual("first"); |         expect(firstSub.attributeName).toEqual("first"); | ||||||
| @@ -173,17 +173,17 @@ describe("Parser", () => { | |||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         expect(rootExp.constructor.name).toEqual("AndExp"); |         expect(rootExp.constructor.name).toEqual("AndExp"); | ||||||
|         const [firstSub, secondSub, thirdSub] = rootExp.subExpressions; |         const [firstSub, secondSub, thirdSub, fourth] = rootExp.subExpressions; | ||||||
|  |  | ||||||
|         expect(firstSub.constructor.name).toEqual("PropertyComparisonExp"); |         expect(firstSub.constructor.name).toEqual("PropertyComparisonExp"); | ||||||
|         expect(firstSub.propertyName).toEqual('isArchived'); |         expect(firstSub.propertyName).toEqual('isArchived'); | ||||||
|  |  | ||||||
|         expect(secondSub.constructor.name).toEqual("OrExp"); |         expect(thirdSub.constructor.name).toEqual("OrExp"); | ||||||
|         expect(secondSub.subExpressions[0].constructor.name).toEqual("NoteFlatTextExp"); |         expect(thirdSub.subExpressions[0].constructor.name).toEqual("NoteFlatTextExp"); | ||||||
|         expect(secondSub.subExpressions[0].tokens).toEqual(["hello"]); |         expect(thirdSub.subExpressions[0].tokens).toEqual(["hello"]); | ||||||
|  |  | ||||||
|         expect(thirdSub.constructor.name).toEqual("LabelComparisonExp"); |         expect(fourth.constructor.name).toEqual("LabelComparisonExp"); | ||||||
|         expect(thirdSub.attributeName).toEqual("mylabel"); |         expect(fourth.attributeName).toEqual("mylabel"); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it("label sub-expression", () => { |     it("label sub-expression", () => { | ||||||
| @@ -196,8 +196,8 @@ describe("Parser", () => { | |||||||
|         expect(rootExp.constructor.name).toEqual("AndExp"); |         expect(rootExp.constructor.name).toEqual("AndExp"); | ||||||
|         assertIsArchived(rootExp.subExpressions[0]); |         assertIsArchived(rootExp.subExpressions[0]); | ||||||
|  |  | ||||||
|         expect(rootExp.subExpressions[1].constructor.name).toEqual("OrExp"); |         expect(rootExp.subExpressions[2].constructor.name).toEqual("OrExp"); | ||||||
|         const [firstSub, secondSub] = rootExp.subExpressions[1].subExpressions; |         const [firstSub, secondSub] = rootExp.subExpressions[2].subExpressions; | ||||||
|  |  | ||||||
|         expect(firstSub.constructor.name).toEqual("LabelComparisonExp"); |         expect(firstSub.constructor.name).toEqual("LabelComparisonExp"); | ||||||
|         expect(firstSub.attributeName).toEqual("first"); |         expect(firstSub.attributeName).toEqual("first"); | ||||||
| @@ -222,8 +222,8 @@ describe("Parser", () => { | |||||||
|         expect(rootExp.constructor.name).toEqual("AndExp"); |         expect(rootExp.constructor.name).toEqual("AndExp"); | ||||||
|         assertIsArchived(rootExp.subExpressions[0]); |         assertIsArchived(rootExp.subExpressions[0]); | ||||||
|  |  | ||||||
|         expect(rootExp.subExpressions[1].constructor.name).toEqual("AndExp"); |         expect(rootExp.subExpressions[2].constructor.name).toEqual("AndExp"); | ||||||
|         const [firstSub, secondSub, thirdSub] = rootExp.subExpressions[1].subExpressions; |         const [firstSub, secondSub, thirdSub] = rootExp.subExpressions[2].subExpressions; | ||||||
|  |  | ||||||
|         expect(firstSub.constructor.name).toEqual("AttributeExistsExp"); |         expect(firstSub.constructor.name).toEqual("AttributeExistsExp"); | ||||||
|         expect(firstSub.attributeName).toEqual("first"); |         expect(firstSub.attributeName).toEqual("first"); | ||||||
| @@ -290,10 +290,11 @@ describe("Invalid expressions", () => { | |||||||
|  |  | ||||||
|         expect(rootExp.constructor.name).toEqual("AndExp"); |         expect(rootExp.constructor.name).toEqual("AndExp"); | ||||||
|         assertIsArchived(rootExp.subExpressions[0]); |         assertIsArchived(rootExp.subExpressions[0]); | ||||||
|         expect(rootExp.subExpressions[1].constructor.name).toEqual("LabelComparisonExp"); |  | ||||||
|         expect(rootExp.subExpressions[1].attributeType).toEqual("label"); |         expect(rootExp.subExpressions[2].constructor.name).toEqual("LabelComparisonExp"); | ||||||
|         expect(rootExp.subExpressions[1].attributeName).toEqual("first"); |         expect(rootExp.subExpressions[2].attributeType).toEqual("label"); | ||||||
|         expect(rootExp.subExpressions[1].comparator).toBeTruthy(); |         expect(rootExp.subExpressions[2].attributeName).toEqual("first"); | ||||||
|  |         expect(rootExp.subExpressions[2].comparator).toBeTruthy(); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     it("searching by relation without note property", () => { |     it("searching by relation without note property", () => { | ||||||
|   | |||||||
| @@ -211,11 +211,6 @@ class BNote extends AbstractBeccaEntity { | |||||||
|         return this._getContent(); |         return this._getContent(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** @returns {{dateModified, utcDateModified}} */ |  | ||||||
|     getContentMetadata() { |  | ||||||
|         return sql.getRow(`SELECT dateModified, utcDateModified FROM blobs WHERE blobId = ?`, [this.blobId]); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** @returns {*} */ |     /** @returns {*} */ | ||||||
|     getJsonContent() { |     getJsonContent() { | ||||||
|         const content = this.getContent(); |         const content = this.getContent(); | ||||||
| @@ -1571,7 +1566,6 @@ class BNote extends AbstractBeccaEntity { | |||||||
|     saveRevision() { |     saveRevision() { | ||||||
|         return sql.transactional(() => { |         return sql.transactional(() => { | ||||||
|             let noteContent = this.getContent(); |             let noteContent = this.getContent(); | ||||||
|             const contentMetadata = this.getContentMetadata(); |  | ||||||
|  |  | ||||||
|             const revision = new BRevision({ |             const revision = new BRevision({ | ||||||
|                 noteId: this.noteId, |                 noteId: this.noteId, | ||||||
| @@ -1580,14 +1574,10 @@ class BNote extends AbstractBeccaEntity { | |||||||
|                 type: this.type, |                 type: this.type, | ||||||
|                 mime: this.mime, |                 mime: this.mime, | ||||||
|                 isProtected: this.isProtected, |                 isProtected: this.isProtected, | ||||||
|                 utcDateLastEdited: this.utcDateModified > contentMetadata.utcDateModified |                 utcDateLastEdited: this.utcDateModified, | ||||||
|                     ? this.utcDateModified |  | ||||||
|                     : contentMetadata.utcDateModified, |  | ||||||
|                 utcDateCreated: dateUtils.utcNowDateTime(), |                 utcDateCreated: dateUtils.utcNowDateTime(), | ||||||
|                 utcDateModified: dateUtils.utcNowDateTime(), |                 utcDateModified: dateUtils.utcNowDateTime(), | ||||||
|                 dateLastEdited: this.dateModified > contentMetadata.dateModified |                 dateLastEdited: this.dateModified, | ||||||
|                     ? this.dateModified |  | ||||||
|                     : contentMetadata.dateModified, |  | ||||||
|                 dateCreated: dateUtils.localNowDateTime() |                 dateCreated: dateUtils.localNowDateTime() | ||||||
|             }, true); |             }, true); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -802,6 +802,12 @@ components: | |||||||
|         branchId: |         branchId: | ||||||
|           $ref: '#/components/schemas/EntityId' |           $ref: '#/components/schemas/EntityId' | ||||||
|           description: DON'T specify unless you want to force a specific branchId |           description: DON'T specify unless you want to force a specific branchId | ||||||
|  |         dateCreated: | ||||||
|  |           $ref: '#/components/schemas/LocalDateTime' | ||||||
|  |           description: Local timestap of the note creation. Specify only if you want to override the default (current datetime in the current timezone/offset). | ||||||
|  |         utcDateCreated: | ||||||
|  |           $ref: '#/components/schemas/UtcDateTime' | ||||||
|  |           description: UTC timestap of the note creation. Specify only if you want to override the default (current datetime). | ||||||
|     Note: |     Note: | ||||||
|       type: object |       type: object | ||||||
|       properties: |       properties: | ||||||
| @@ -838,13 +844,11 @@ components: | |||||||
|           readOnly: true |           readOnly: true | ||||||
|         dateCreated: |         dateCreated: | ||||||
|           $ref: '#/components/schemas/LocalDateTime' |           $ref: '#/components/schemas/LocalDateTime' | ||||||
|           readOnly: true |  | ||||||
|         dateModified: |         dateModified: | ||||||
|           $ref: '#/components/schemas/LocalDateTime' |           $ref: '#/components/schemas/LocalDateTime' | ||||||
|           readOnly: true |           readOnly: true | ||||||
|         utcDateCreated: |         utcDateCreated: | ||||||
|           $ref: '#/components/schemas/UtcDateTime' |           $ref: '#/components/schemas/UtcDateTime' | ||||||
|           readOnly: true |  | ||||||
|         utcDateModified: |         utcDateModified: | ||||||
|           $ref: '#/components/schemas/UtcDateTime' |           $ref: '#/components/schemas/UtcDateTime' | ||||||
|           readOnly: true |           readOnly: true | ||||||
| @@ -937,11 +941,11 @@ components: | |||||||
|     LocalDateTime: |     LocalDateTime: | ||||||
|       type: string |       type: string | ||||||
|       pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}[\+\-][0-9]{4}' |       pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}[\+\-][0-9]{4}' | ||||||
|       example: 2021-12-31 20:18:11.939+0100 |       example: 2021-12-31 20:18:11.930+0100 | ||||||
|     UtcDateTime: |     UtcDateTime: | ||||||
|       type: string |       type: string | ||||||
|       pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z' |       pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z' | ||||||
|       example: 2021-12-31 19:18:11.939Z |       example: 2021-12-31 19:18:11.930Z | ||||||
|     AppInfo: |     AppInfo: | ||||||
|       type: object |       type: object | ||||||
|       properties: |       properties: | ||||||
|   | |||||||
| @@ -50,7 +50,9 @@ function register(router) { | |||||||
|         'notePosition': [v.notNull, v.isInteger], |         'notePosition': [v.notNull, v.isInteger], | ||||||
|         'prefix': [v.notNull, v.isString], |         'prefix': [v.notNull, v.isString], | ||||||
|         'isExpanded': [v.notNull, v.isBoolean], |         'isExpanded': [v.notNull, v.isBoolean], | ||||||
|         'noteId': [v.notNull, v.isValidEntityId] |         'noteId': [v.notNull, v.isValidEntityId], | ||||||
|  |         'dateCreated': [v.notNull, v.isString, v.isLocalDateTime], | ||||||
|  |         'utcDateCreated': [v.notNull, v.isString, v.isUtcDateTime] | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     eu.route(router, 'post' ,'/etapi/create-note', (req, res, next) => { |     eu.route(router, 'post' ,'/etapi/create-note', (req, res, next) => { | ||||||
| @@ -74,7 +76,9 @@ function register(router) { | |||||||
|     const ALLOWED_PROPERTIES_FOR_PATCH = { |     const ALLOWED_PROPERTIES_FOR_PATCH = { | ||||||
|         'title': [v.notNull, v.isString], |         'title': [v.notNull, v.isString], | ||||||
|         'type': [v.notNull, v.isString], |         'type': [v.notNull, v.isString], | ||||||
|         'mime': [v.notNull, v.isString] |         'mime': [v.notNull, v.isString], | ||||||
|  |         'dateCreated': [v.notNull, v.isString, v.isLocalDateTime], | ||||||
|  |         'utcDateCreated': [v.notNull, v.isString, v.isUtcDateTime] | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     eu.route(router, 'patch' ,'/etapi/notes/:noteId', (req, res, next) => { |     eu.route(router, 'patch' ,'/etapi/notes/:noteId', (req, res, next) => { | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| const noteTypeService = require("../services/note_types"); | const noteTypeService = require("../services/note_types"); | ||||||
|  | const dateUtils = require("../services/date_utils"); | ||||||
|  |  | ||||||
| function mandatory(obj) { | function mandatory(obj) { | ||||||
|     if (obj === undefined ) { |     if (obj === undefined ) { | ||||||
| @@ -22,6 +23,22 @@ function isString(obj) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function isLocalDateTime(obj) { | ||||||
|  |     if (obj === undefined || obj === null) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return dateUtils.validateLocalDateTime(obj); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function isUtcDateTime(obj) { | ||||||
|  |     if (obj === undefined || obj === null) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return dateUtils.validateUtcDateTime(obj); | ||||||
|  | } | ||||||
|  |  | ||||||
| function isBoolean(obj) { | function isBoolean(obj) { | ||||||
|     if (obj === undefined || obj === null) { |     if (obj === undefined || obj === null) { | ||||||
|         return; |         return; | ||||||
| @@ -99,5 +116,7 @@ module.exports = { | |||||||
|     isNoteId, |     isNoteId, | ||||||
|     isNoteType, |     isNoteType, | ||||||
|     isAttributeType, |     isAttributeType, | ||||||
|     isValidEntityId |     isValidEntityId, | ||||||
|  |     isLocalDateTime, | ||||||
|  |     isUtcDateTime | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -120,10 +120,9 @@ class FNote { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async getContent() { |     async getContent() { | ||||||
|         // we're not caching content since these objects are in froca and as such pretty long-lived |         const blob = await this.getBlob(); | ||||||
|         const note = await server.get(`notes/${this.noteId}`); |  | ||||||
|  |  | ||||||
|         return note.content; |         return blob?.content; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async getJsonContent() { |     async getJsonContent() { | ||||||
| @@ -971,6 +970,10 @@ class FNote { | |||||||
|     isOptions() { |     isOptions() { | ||||||
|         return this.noteId.startsWith("_options"); |         return this.noteId.startsWith("_options"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async getMetadata() { | ||||||
|  |         return await server.get(`notes/${this.noteId}/metadata`); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| export default FNote; | export default FNote; | ||||||
|   | |||||||
| @@ -4,8 +4,11 @@ import toastService from "./toast.js"; | |||||||
| import froca from "./froca.js"; | import froca from "./froca.js"; | ||||||
| import utils from "./utils.js"; | import utils from "./utils.js"; | ||||||
|  |  | ||||||
| async function getAndExecuteBundle(noteId, originEntity = null) { | async function getAndExecuteBundle(noteId, originEntity = null, script = null, params = null) { | ||||||
|     const bundle = await server.get(`script/bundle/${noteId}`); |     const bundle = await server.post(`script/bundle/${noteId}`, { | ||||||
|  |         script, | ||||||
|  |         params | ||||||
|  |     }); | ||||||
|  |  | ||||||
|     return await executeBundle(bundle, originEntity); |     return await executeBundle(bundle, originEntity); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -301,6 +301,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain | |||||||
|      * @param {boolean} [params.showNotePath=false] - show also whole note's path as part of the link |      * @param {boolean} [params.showNotePath=false] - show also whole note's path as part of the link | ||||||
|      * @param {boolean} [params.showNoteIcon=false] - show also note icon before the title |      * @param {boolean} [params.showNoteIcon=false] - show also note icon before the title | ||||||
|      * @param {string} [params.title=] - custom link tile with note's title as default |      * @param {string} [params.title=] - custom link tile with note's title as default | ||||||
|  |      * @returns {jQuery} - jQuery element with the link (wrapped in <span>) | ||||||
|      */ |      */ | ||||||
|     this.createLink = linkService.createLink; |     this.createLink = linkService.createLink; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ async function render(note, $el) { | |||||||
|     $el.empty().toggle(renderNoteIds.length > 0); |     $el.empty().toggle(renderNoteIds.length > 0); | ||||||
|  |  | ||||||
|     for (const renderNoteId of renderNoteIds) { |     for (const renderNoteId of renderNoteIds) { | ||||||
|         const bundle = await server.get(`script/bundle/${renderNoteId}`); |         const bundle = await server.post(`script/bundle/${renderNoteId}`); | ||||||
|  |  | ||||||
|         const $scriptContainer = $('<div>'); |         const $scriptContainer = $('<div>'); | ||||||
|         $el.append($scriptContainer); |         $el.append($scriptContainer); | ||||||
|   | |||||||
| @@ -125,6 +125,13 @@ async function handleMessage(event) { | |||||||
|     else if (message.type === 'toast') { |     else if (message.type === 'toast') { | ||||||
|         toastService.showMessage(message.message); |         toastService.showMessage(message.message); | ||||||
|     } |     } | ||||||
|  |     else if (message.type === 'execute-script') { | ||||||
|  |         const bundleService = (await import("../services/bundle.js")).default; | ||||||
|  |         const froca = (await import("../services/froca.js")).default; | ||||||
|  |         const originEntity = message.originEntityId ? await froca.getNote(message.originEntityId) : null; | ||||||
|  |  | ||||||
|  |         bundleService.getAndExecuteBundle(message.currentNoteId, originEntity, message.script, message.params); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| let entityChangeIdReachedListeners = []; | let entityChangeIdReachedListeners = []; | ||||||
|   | |||||||
| @@ -105,7 +105,7 @@ export default class CalendarWidget extends RightDropdownButtonWidget { | |||||||
|  |  | ||||||
|         if (dateNoteId) { |         if (dateNoteId) { | ||||||
|             $newDay.addClass('calendar-date-exists'); |             $newDay.addClass('calendar-date-exists'); | ||||||
|             $newDay.attr("href", `#root/dateNoteId`); |             $newDay.attr("href", `#root/${dateNoteId}`); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (this.isEqual(this.date, this.activeDate)) { |         if (this.isEqual(this.date, this.activeDate)) { | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ export default class NoteLauncher extends AbstractLauncher { | |||||||
|     async launch(evt) { |     async launch(evt) { | ||||||
|         // await because subclass overrides can be async |         // await because subclass overrides can be async | ||||||
|         const targetNoteId = await this.getTargetNoteId(); |         const targetNoteId = await this.getTargetNoteId(); | ||||||
|         if (!targetNoteId) { |         if (!targetNoteId || evt.which === 3) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,6 +17,9 @@ export default class OpenNoteButtonWidget extends OnClickButtonWidget { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async launch(evt) { |     async launch(evt) { | ||||||
|  |         if (evt.which === 3) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|         const ctrlKey = utils.isCtrlKey(evt); |         const ctrlKey = utils.isCtrlKey(evt); | ||||||
|  |  | ||||||
|         if ((evt.which === 1 && ctrlKey) || evt.which === 2) { |         if ((evt.which === 1 && ctrlKey) || evt.which === 2) { | ||||||
|   | |||||||
| @@ -115,7 +115,7 @@ export default class FindInCode { | |||||||
|  |  | ||||||
|         return { |         return { | ||||||
|             totalFound, |             totalFound, | ||||||
|             currentFound: currentFound + 1 |             currentFound: Math.min(currentFound + 1, totalFound) | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -39,7 +39,7 @@ export default class FindInHtml { | |||||||
|  |  | ||||||
|                             res({ |                             res({ | ||||||
|                                 totalFound: this.$results.length, |                                 totalFound: this.$results.length, | ||||||
|                                 currentFound: 1 |                                 currentFound: Math.min(1, this.$results.length) | ||||||
|                             }); |                             }); | ||||||
|                         } |                         } | ||||||
|                     }); |                     }); | ||||||
|   | |||||||
| @@ -59,7 +59,7 @@ export default class FindInText { | |||||||
|  |  | ||||||
|         return { |         return { | ||||||
|             totalFound, |             totalFound, | ||||||
|             currentFound: currentFound + 1 |             currentFound: Math.min(currentFound + 1, totalFound) | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -128,8 +128,8 @@ export default class NoteInfoWidget extends NoteContextAwareWidget { | |||||||
|             .attr("title", metadata.dateCreated); |             .attr("title", metadata.dateCreated); | ||||||
|  |  | ||||||
|         this.$dateModified |         this.$dateModified | ||||||
|             .text(metadata.combinedDateModified.substr(0, 16)) |             .text(metadata.dateModified.substr(0, 16)) | ||||||
|             .attr("title", metadata.combinedDateModified); |             .attr("title", metadata.dateModified); | ||||||
|  |  | ||||||
|         this.$type.text(note.type); |         this.$type.text(note.type); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -94,13 +94,12 @@ function createNote(req) { | |||||||
|     clipType = htmlSanitizer.sanitize(clipType); |     clipType = htmlSanitizer.sanitize(clipType); | ||||||
|  |  | ||||||
|     const clipperInbox = getClipperInboxNote(); |     const clipperInbox = getClipperInboxNote(); | ||||||
|     const dailyNote = dateNoteService.getDayNote(dateUtils.localNowDate()); |  | ||||||
|     pageUrl = htmlSanitizer.sanitizeUrl(pageUrl); |     pageUrl = htmlSanitizer.sanitizeUrl(pageUrl); | ||||||
|     let note = findClippingNote(clipperInbox, pageUrl, clipType); |     let note = findClippingNote(clipperInbox, pageUrl, clipType); | ||||||
|  |  | ||||||
|     if (!note) { |     if (!note) { | ||||||
|         note = noteService.createNewNote({ |         note = noteService.createNewNote({ | ||||||
|             parentNoteId: dailyNote.noteId, |             parentNoteId: clipperInbox.noteId, | ||||||
|             title, |             title, | ||||||
|             content: '', |             content: '', | ||||||
|             type: 'text' |             type: 'text' | ||||||
|   | |||||||
| @@ -21,11 +21,12 @@ function getNoteBlob(req) { | |||||||
|  |  | ||||||
| function getNoteMetadata(req) { | function getNoteMetadata(req) { | ||||||
|     const note = becca.getNoteOrThrow(req.params.noteId); |     const note = becca.getNoteOrThrow(req.params.noteId); | ||||||
|     const contentMetadata = note.getContentMetadata(); |  | ||||||
|  |  | ||||||
|     return { |     return { | ||||||
|         dateCreated: note.dateCreated, |         dateCreated: note.dateCreated, | ||||||
|         combinedDateModified: note.utcDateModified > contentMetadata.utcDateModified ? note.dateModified : contentMetadata.dateModified |         utcDateCreated: note.utcDateCreated, | ||||||
|  |         dateModified: note.dateModified, | ||||||
|  |         utcDateModified: note.utcDateModified, | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -107,8 +107,9 @@ function getRelationBundles(req) { | |||||||
|  |  | ||||||
| function getBundle(req) { | function getBundle(req) { | ||||||
|     const note = becca.getNote(req.params.noteId); |     const note = becca.getNote(req.params.noteId); | ||||||
|  |     const {script, params} = req.body; | ||||||
|  |  | ||||||
|     return scriptService.getScriptBundleForFrontend(note); |     return scriptService.getScriptBundleForFrontend(note, script, params); | ||||||
| } | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|   | |||||||
| @@ -302,7 +302,7 @@ function register(app) { | |||||||
|     apiRoute(PST, '/api/script/run/:noteId', scriptRoute.run); |     apiRoute(PST, '/api/script/run/:noteId', scriptRoute.run); | ||||||
|     apiRoute(GET, '/api/script/startup', scriptRoute.getStartupBundles); |     apiRoute(GET, '/api/script/startup', scriptRoute.getStartupBundles); | ||||||
|     apiRoute(GET, '/api/script/widgets', scriptRoute.getWidgetBundles); |     apiRoute(GET, '/api/script/widgets', scriptRoute.getWidgetBundles); | ||||||
|     apiRoute(GET, '/api/script/bundle/:noteId', scriptRoute.getBundle); |     apiRoute(PST, '/api/script/bundle/:noteId', scriptRoute.getBundle); | ||||||
|     apiRoute(GET, '/api/script/relation/:noteId/:relationName', scriptRoute.getRelationBundles); |     apiRoute(GET, '/api/script/relation/:noteId/:relationName', scriptRoute.getRelationBundles); | ||||||
|  |  | ||||||
|     // no CSRF since this is called from android app |     // no CSRF since this is called from android app | ||||||
|   | |||||||
| @@ -529,6 +529,48 @@ function BackendScriptApi(currentNote, apiParams) { | |||||||
|      */ |      */ | ||||||
|     this.exportSubtreeToZipFile = async (noteId, format, zipFilePath) => await exportService.exportToZipFile(noteId, format, zipFilePath); |     this.exportSubtreeToZipFile = async (noteId, format, zipFilePath) => await exportService.exportToZipFile(noteId, format, zipFilePath); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Executes given anonymous function on the frontend(s). | ||||||
|  |      * Internally this serializes the anonymous function into string and sends it to frontend(s) via WebSocket. | ||||||
|  |      * Note that there can be multiple connected frontend instances (e.g. in different tabs). In such case, all | ||||||
|  |      * instances execute the given function. | ||||||
|  |      * | ||||||
|  |      * @method | ||||||
|  |      * @param {string} script - script to be executed on the frontend | ||||||
|  |      * @param {Array.<?>} params - list of parameters to the anonymous function to be sent to frontend | ||||||
|  |      * @returns {undefined} - no return value is provided. | ||||||
|  |      */ | ||||||
|  |     this.runOnFrontend = async (script, params = []) => { | ||||||
|  |         if (typeof script === "function") { | ||||||
|  |             script = script.toString(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         ws.sendMessageToAllClients({ | ||||||
|  |             type: 'execute-script', | ||||||
|  |             script: script, | ||||||
|  |             params: prepareParams(params), | ||||||
|  |             startNoteId: this.startNote.noteId, | ||||||
|  |             currentNoteId: this.currentNote.noteId, | ||||||
|  |             originEntityName: "notes", // currently there's no other entity on the frontend which can trigger event | ||||||
|  |             originEntityId: this.originEntity?.noteId || null | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         function prepareParams(params) { | ||||||
|  |             if (!params) { | ||||||
|  |                 return params; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return params.map(p => { | ||||||
|  |                 if (typeof p === "function") { | ||||||
|  |                     return `!@#Function: ${p.toString()}`; | ||||||
|  |                 } | ||||||
|  |                 else { | ||||||
|  |                     return p; | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * This object contains "at your risk" and "no BC guarantees" objects for advanced use cases. |      * This object contains "at your risk" and "no BC guarantees" objects for advanced use cases. | ||||||
|      * |      * | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| module.exports = { buildDate:"2023-08-16T23:02:15+02:00", buildRevision: "3f7a5504c77263a7118cede5c0d9b450ba37f424" }; | module.exports = { buildDate:"2023-09-06T23:57:29+02:00", buildRevision: "6fa9d996e84f87fcb73c3388a5170affd2c2f7cc" }; | ||||||
|   | |||||||
| @@ -758,7 +758,7 @@ class ConsistencyChecks { | |||||||
|             return `${tableName}: ${count}`; |             return `${tableName}: ${count}`; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const tables = [ "notes", "revisions", "attachments", "branches", "attributes", "etapi_tokens" ]; |         const tables = [ "notes", "revisions", "attachments", "branches", "attributes", "etapi_tokens", "blobs" ]; | ||||||
|  |  | ||||||
|         log.info(`Table counts: ${tables.map(tableName => getTableRowCount(tableName)).join(", ")}`); |         log.info(`Table counts: ${tables.map(tableName => getTableRowCount(tableName)).join(", ")}`); | ||||||
|     } |     } | ||||||
| @@ -767,7 +767,13 @@ class ConsistencyChecks { | |||||||
|         let elapsedTimeMs; |         let elapsedTimeMs; | ||||||
|  |  | ||||||
|         await syncMutexService.doExclusively(() => { |         await syncMutexService.doExclusively(() => { | ||||||
|             elapsedTimeMs = this.runChecksInner(); |             const startTimeMs = Date.now(); | ||||||
|  |  | ||||||
|  |             this.runDbDiagnostics(); | ||||||
|  |  | ||||||
|  |             this.runAllChecksAndFixers(); | ||||||
|  |  | ||||||
|  |             elapsedTimeMs = Date.now() - startTimeMs; | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         if (this.unrecoveredConsistencyErrors) { |         if (this.unrecoveredConsistencyErrors) { | ||||||
| @@ -781,16 +787,6 @@ class ConsistencyChecks { | |||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     runChecksInner() { |  | ||||||
|         const startTimeMs = Date.now(); |  | ||||||
|  |  | ||||||
|         this.runDbDiagnostics(); |  | ||||||
|  |  | ||||||
|         this.runAllChecksAndFixers(); |  | ||||||
|  |  | ||||||
|         return Date.now() - startTimeMs; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| function getBlankContent(isProtected, type, mime) { | function getBlankContent(isProtected, type, mime) { | ||||||
| @@ -825,11 +821,6 @@ async function runOnDemandChecks(autoFix) { | |||||||
|     await consistencyChecks.runChecks(); |     await consistencyChecks.runChecks(); | ||||||
| } | } | ||||||
|  |  | ||||||
| function runOnDemandChecksWithoutExclusiveLock(autoFix) { |  | ||||||
|     const consistencyChecks = new ConsistencyChecks(autoFix); |  | ||||||
|     consistencyChecks.runChecksInner(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function runEntityChangesChecks() { | function runEntityChangesChecks() { | ||||||
|     const consistencyChecks = new ConsistencyChecks(true); |     const consistencyChecks = new ConsistencyChecks(true); | ||||||
|     consistencyChecks.findEntityChangeIssues(); |     consistencyChecks.findEntityChangeIssues(); | ||||||
| @@ -844,6 +835,5 @@ sqlInit.dbReady.then(() => { | |||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     runOnDemandChecks, |     runOnDemandChecks, | ||||||
|     runOnDemandChecksWithoutExclusiveLock, |  | ||||||
|     runEntityChangesChecks |     runEntityChangesChecks | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -1,6 +1,9 @@ | |||||||
| const dayjs = require('dayjs'); | const dayjs = require('dayjs'); | ||||||
| const cls = require('./cls'); | const cls = require('./cls'); | ||||||
|  |  | ||||||
|  | const LOCAL_DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss.SSSZZ'; | ||||||
|  | const UTC_DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ssZ'; | ||||||
|  |  | ||||||
| function utcNowDateTime() { | function utcNowDateTime() { | ||||||
|     return utcDateTimeStr(new Date()); |     return utcDateTimeStr(new Date()); | ||||||
| } | } | ||||||
| @@ -10,7 +13,7 @@ function utcNowDateTime() { | |||||||
| // "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() { | ||||||
|     return cls.getLocalNowDateTime() |     return cls.getLocalNowDateTime() | ||||||
|         || dayjs().format('YYYY-MM-DD HH:mm:ss.SSSZZ') |         || dayjs().format(LOCAL_DATETIME_FORMAT) | ||||||
| } | } | ||||||
|  |  | ||||||
| function localNowDate() { | function localNowDate() { | ||||||
| @@ -62,6 +65,36 @@ function getDateTimeForFile() { | |||||||
|     return new Date().toISOString().substr(0, 19).replace(/:/g, ''); |     return new Date().toISOString().substr(0, 19).replace(/:/g, ''); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function validateLocalDateTime(str) { | ||||||
|  |     if (!str) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}[+-][0-9]{4}/.test(str)) { | ||||||
|  |         return `Invalid local date time format in '${str}'. Correct format shoud follow example: '2023-08-21 23:38:51.110+0200'`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     if (!dayjs(str, LOCAL_DATETIME_FORMAT)) { | ||||||
|  |         return `Date '${str}' appears to be in the correct format, but cannot be parsed. It likely represents an invalid date.`; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function validateUtcDateTime(str) { | ||||||
|  |     if (!str) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z/.test(str)) { | ||||||
|  |         return `Invalid UTC date time format in '${str}'. Correct format shoud follow example: '2023-08-21 23:38:51.110Z'`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     if (!dayjs(str, UTC_DATETIME_FORMAT)) { | ||||||
|  |         return `Date '${str}' appears to be in the correct format, but cannot be parsed. It likely represents an invalid date.`; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     utcNowDateTime, |     utcNowDateTime, | ||||||
|     localNowDateTime, |     localNowDateTime, | ||||||
| @@ -70,5 +103,7 @@ module.exports = { | |||||||
|     utcDateTimeStr, |     utcDateTimeStr, | ||||||
|     parseDateTime, |     parseDateTime, | ||||||
|     parseLocalDate, |     parseLocalDate, | ||||||
|     getDateTimeForFile |     getDateTimeForFile, | ||||||
|  |     validateLocalDateTime, | ||||||
|  |     validateUtcDateTime | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -15,6 +15,12 @@ function putEntityChangeWithInstanceId(origEntityChange, instanceId) { | |||||||
|     putEntityChange(ec); |     putEntityChange(ec); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function putEntityChangeWithForcedChange(origEntityChange) { | ||||||
|  |     const ec = {...origEntityChange, changeId: null}; | ||||||
|  |  | ||||||
|  |     putEntityChange(ec); | ||||||
|  | } | ||||||
|  |  | ||||||
| function putEntityChange(origEntityChange) { | function putEntityChange(origEntityChange) { | ||||||
|     const ec = {...origEntityChange}; |     const ec = {...origEntityChange}; | ||||||
|  |  | ||||||
| @@ -66,13 +72,37 @@ function putEntityChangeForOtherInstances(ec) { | |||||||
| function addEntityChangesForSector(entityName, sector) { | function addEntityChangesForSector(entityName, sector) { | ||||||
|     const entityChanges = sql.getRows(`SELECT * FROM entity_changes WHERE entityName = ? AND SUBSTR(entityId, 1, 1) = ?`, [entityName, sector]); |     const entityChanges = sql.getRows(`SELECT * FROM entity_changes WHERE entityName = ? AND SUBSTR(entityId, 1, 1) = ?`, [entityName, sector]); | ||||||
|  |  | ||||||
|  |     let entitiesInserted = entityChanges.length; | ||||||
|  |  | ||||||
|     sql.transactional(() => { |     sql.transactional(() => { | ||||||
|  |         if (entityName === 'blobs') { | ||||||
|  |             entitiesInserted += addEntityChangesForDependingEntity(sector, 'notes', 'noteId'); | ||||||
|  |             entitiesInserted += addEntityChangesForDependingEntity(sector, 'attachments', 'attachmentId'); | ||||||
|  |             entitiesInserted += addEntityChangesForDependingEntity(sector, 'revisions', 'revisionId'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         for (const ec of entityChanges) { |         for (const ec of entityChanges) { | ||||||
|             putEntityChange(ec); |             putEntityChangeWithForcedChange(ec); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     log.info(`Added sector ${sector} of '${entityName}' (${entityChanges.length} entities) to the sync queue.`); |     log.info(`Added sector ${sector} of '${entityName}' (${entitiesInserted} entities) to the sync queue.`); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function addEntityChangesForDependingEntity(sector, tableName, primaryKeyColumn) { | ||||||
|  |     // problem in blobs might be caused by problem in entity referencing the blob | ||||||
|  |     const dependingEntityChanges = sql.getRows(` | ||||||
|  |                 SELECT dep_change.*  | ||||||
|  |                 FROM entity_changes orig_sector | ||||||
|  |                 JOIN ${tableName} ON ${tableName}.blobId = orig_sector.entityId | ||||||
|  |                 JOIN entity_changes dep_change ON dep_change.entityName = '${tableName}' AND dep_change.entityId = ${tableName}.${primaryKeyColumn} | ||||||
|  |                 WHERE orig_sector.entityName = 'blobs' AND SUBSTR(orig_sector.entityId, 1, 1) = ?`, [sector]); | ||||||
|  |  | ||||||
|  |     for (const ec of dependingEntityChanges) { | ||||||
|  |         putEntityChangeWithForcedChange(ec); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return dependingEntityChanges.length; | ||||||
| } | } | ||||||
|  |  | ||||||
| function cleanupEntityChangesForMissingEntities(entityName, entityPrimaryKey) { | function cleanupEntityChangesForMissingEntities(entityName, entityPrimaryKey) { | ||||||
| @@ -161,6 +191,7 @@ function recalculateMaxEntityChangeId() { | |||||||
| module.exports = { | module.exports = { | ||||||
|     putNoteReorderingEntityChange, |     putNoteReorderingEntityChange, | ||||||
|     putEntityChangeForOtherInstances, |     putEntityChangeForOtherInstances, | ||||||
|  |     putEntityChangeWithForcedChange, | ||||||
|     putEntityChange, |     putEntityChange, | ||||||
|     putEntityChangeWithInstanceId, |     putEntityChangeWithInstanceId, | ||||||
|     fillAllEntityChanges, |     fillAllEntityChanges, | ||||||
|   | |||||||
| @@ -39,7 +39,7 @@ function setEntityChangesAsErased(entityChanges) { | |||||||
|         ec.isErased = true; |         ec.isErased = true; | ||||||
|         ec.utcDateChanged = dateUtils.utcNowDateTime(); |         ec.utcDateChanged = dateUtils.utcNowDateTime(); | ||||||
|  |  | ||||||
|         entityChangesService.putEntityChange(ec); |         entityChangesService.putEntityChangeWithForcedChange(ec); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,8 +9,8 @@ const appInfo = require('./app_info'); | |||||||
| async function migrate() { | async function migrate() { | ||||||
|     const currentDbVersion = getDbVersion(); |     const currentDbVersion = getDbVersion(); | ||||||
|  |  | ||||||
|     if (currentDbVersion < 183) { |     if (currentDbVersion < 214) { | ||||||
|         log.error("Direct migration from your current version is not supported. Please upgrade to the latest v0.47.X first and only then to this version."); |         log.error("Direct migration from your current version is not supported. Please upgrade to the latest v0.60.X first and only then to this version."); | ||||||
|  |  | ||||||
|         utils.crash(); |         utils.crash(); | ||||||
|         return; |         return; | ||||||
| @@ -18,9 +18,9 @@ async function migrate() { | |||||||
|  |  | ||||||
|     // backup before attempting migration |     // backup before attempting migration | ||||||
|     await backupService.backupNow( |     await backupService.backupNow( | ||||||
|         // creating a special backup for versions 0.60.X and older, the changes in 0.61 are major. |         // creating a special backup for versions 0.60.X, the changes in 0.61 are major. | ||||||
|         currentDbVersion < 214 |         currentDbVersion === 214 | ||||||
|             ? `before-migration-v${currentDbVersion}` |             ? `before-migration-v060` | ||||||
|             : 'before-migration' |             : 'before-migration' | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,4 @@ | |||||||
| const sql = require('./sql'); | const sql = require('./sql'); | ||||||
| const sqlInit = require('./sql_init'); |  | ||||||
| const optionService = require('./options'); | const optionService = require('./options'); | ||||||
| const dateUtils = require('./date_utils'); | const dateUtils = require('./date_utils'); | ||||||
| const entityChangesService = require('./entity_changes'); | const entityChangesService = require('./entity_changes'); | ||||||
| @@ -169,6 +168,15 @@ function createNewNote(params) { | |||||||
|         throw new Error(`Note content must be set`); |         throw new Error(`Note content must be set`); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     let error; | ||||||
|  |     if (error = dateUtils.validateLocalDateTime(params.dateCreated)) { | ||||||
|  |         throw new Error(error); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (error = dateUtils.validateUtcDateTime(params.utcDateCreated)) { | ||||||
|  |         throw new Error(error); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return sql.transactional(() => { |     return sql.transactional(() => { | ||||||
|         let note, branch, isEntityEventsDisabled; |         let note, branch, isEntityEventsDisabled; | ||||||
|  |  | ||||||
| @@ -189,7 +197,9 @@ function createNewNote(params) { | |||||||
|                 title: params.title, |                 title: params.title, | ||||||
|                 isProtected: !!params.isProtected, |                 isProtected: !!params.isProtected, | ||||||
|                 type: params.type, |                 type: params.type, | ||||||
|                 mime: deriveMime(params.type, params.mime) |                 mime: deriveMime(params.type, params.mime), | ||||||
|  |                 dateCreated: params.dateCreated, | ||||||
|  |                 utcDateCreated: params.utcDateCreated | ||||||
|             }).save(); |             }).save(); | ||||||
|  |  | ||||||
|             note.setContent(params.content); |             note.setContent(params.content); | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ function getOptionOrNull(name) { | |||||||
|         option = becca.getOption(name); |         option = becca.getOption(name); | ||||||
|     } else { |     } else { | ||||||
|         // e.g. in initial sync becca is not loaded because DB is not initialized |         // e.g. in initial sync becca is not loaded because DB is not initialized | ||||||
|         option = sql.getRow("SELECT * FROM options WHERE name = ?", name); |         option = sql.getRow("SELECT * FROM options WHERE name = ?", [name]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return option ? option.value : null; |     return option ? option.value : null; | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ function executeNote(note, apiParams) { | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const bundle = getScriptBundle(note); |     const bundle = getScriptBundle(note, true, 'backend'); | ||||||
|  |  | ||||||
|     return executeBundle(bundle, apiParams); |     return executeBundle(bundle, apiParams); | ||||||
| } | } | ||||||
| @@ -68,9 +68,9 @@ function executeScript(script, params, startNoteId, currentNoteId, originEntityN | |||||||
|  |  | ||||||
|     // 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 overrideContent = `return (${script}\r\n)(${getParams(params)})`; | ||||||
|  |  | ||||||
|     const bundle = getScriptBundle(currentNote, true, null, [], backendOverrideContent); |     const bundle = getScriptBundle(currentNote, true, 'backend', [], overrideContent); | ||||||
|  |  | ||||||
|     return executeBundle(bundle, { startNote, originEntity }); |     return executeBundle(bundle, { startNote, originEntity }); | ||||||
| } | } | ||||||
| @@ -96,9 +96,17 @@ function getParams(params) { | |||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @param {BNote} note |  * @param {BNote} note | ||||||
|  |  * @param {string} [script] | ||||||
|  |  * @param {Array} [params] | ||||||
|  */ |  */ | ||||||
| function getScriptBundleForFrontend(note) { | function getScriptBundleForFrontend(note, script, params) { | ||||||
|     const bundle = getScriptBundle(note); |     let overrideContent = null; | ||||||
|  |  | ||||||
|  |     if (script) { | ||||||
|  |         overrideContent = `return (${script}\r\n)(${getParams(params)})`; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const bundle = getScriptBundle(note, true, 'frontend', [], overrideContent); | ||||||
|  |  | ||||||
|     if (!bundle) { |     if (!bundle) { | ||||||
|         return; |         return; | ||||||
| @@ -119,9 +127,9 @@ function getScriptBundleForFrontend(note) { | |||||||
|  * @param {boolean} [root=true] |  * @param {boolean} [root=true] | ||||||
|  * @param {string|null} [scriptEnv] |  * @param {string|null} [scriptEnv] | ||||||
|  * @param {string[]} [includedNoteIds] |  * @param {string[]} [includedNoteIds] | ||||||
|  * @param {string|null} [backendOverrideContent] |  * @param {string|null} [overrideContent] | ||||||
|  */ |  */ | ||||||
| function getScriptBundle(note, root = true, scriptEnv = null, includedNoteIds = [], backendOverrideContent = null) { | function getScriptBundle(note, root = true, scriptEnv = null, includedNoteIds = [], overrideContent = null) { | ||||||
|     if (!note.isContentAvailable()) { |     if (!note.isContentAvailable()) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| @@ -134,12 +142,6 @@ function getScriptBundle(note, root = true, scriptEnv = null, includedNoteIds = | |||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (root) { |  | ||||||
|         scriptEnv = backendOverrideContent |  | ||||||
|             ? 'backend' |  | ||||||
|             : note.getScriptEnv(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (note.type !== 'file' && !root && scriptEnv !== note.getScriptEnv()) { |     if (note.type !== 'file' && !root && scriptEnv !== note.getScriptEnv()) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| @@ -180,7 +182,7 @@ function getScriptBundle(note, root = true, scriptEnv = null, includedNoteIds = | |||||||
| apiContext.modules['${note.noteId}'] = { exports: {} }; | apiContext.modules['${note.noteId}'] = { exports: {} }; | ||||||
| ${root ? 'return ' : ''}${isFrontend ? 'await' : ''} ((${isFrontend ? 'async' : ''} function(exports, module, require, api${modules.length > 0 ? ', ' : ''}${modules.map(child => sanitizeVariableName(child.title)).join(', ')}) { | ${root ? 'return ' : ''}${isFrontend ? 'await' : ''} ((${isFrontend ? 'async' : ''} function(exports, module, require, api${modules.length > 0 ? ', ' : ''}${modules.map(child => sanitizeVariableName(child.title)).join(', ')}) { | ||||||
| try { | try { | ||||||
| ${backendOverrideContent || note.getContent()}; | ${overrideContent || note.getContent()}; | ||||||
| } catch (e) { throw new Error("Load of script note \\"${note.title}\\" (${note.noteId}) failed with: " + e.message); } | } catch (e) { throw new Error("Load of script note \\"${note.title}\\" (${note.noteId}) failed with: " + e.message); } | ||||||
| for (const exportKey in exports) module.exports[exportKey] = exports[exportKey]; | for (const exportKey in exports) module.exports[exportKey] = exports[exportKey]; | ||||||
| return module.exports; | return module.exports; | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ function lex(str) { | |||||||
|     let currentWord = ''; |     let currentWord = ''; | ||||||
|  |  | ||||||
|     function isSymbolAnOperator(chr) { |     function isSymbolAnOperator(chr) { | ||||||
|         return ['=', '*', '>', '<', '!', "-", "+", '%'].includes(chr); |         return ['=', '*', '>', '<', '!', "-", "+", '%', ','].includes(chr); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function isPreviousSymbolAnOperator() { |     function isPreviousSymbolAnOperator() { | ||||||
| @@ -128,6 +128,10 @@ function lex(str) { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (chr === ',') { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         currentWord += chr; |         currentWord += chr; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -40,13 +40,12 @@ function updateNormalEntity(remoteEC, remoteEntityRow, instanceId) { | |||||||
|         // on this side, we can't unerase the entity, so force the entity to be erased on the other side. |         // on this side, we can't unerase the entity, so force the entity to be erased on the other side. | ||||||
|         entityChangesService.putEntityChangeForOtherInstances(localEC); |         entityChangesService.putEntityChangeForOtherInstances(localEC); | ||||||
|  |  | ||||||
|  |         return false; | ||||||
|  |     } else if (localEC?.isErased && remoteEC.isErased) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (!localEC |     if (!localEC || localEC.utcDateChanged <= remoteEC.utcDateChanged) { | ||||||
|         || localEC.utcDateChanged < remoteEC.utcDateChanged |  | ||||||
|         || (localEC.utcDateChanged === remoteEC.utcDateChanged && localEC.hash !== remoteEC.hash) // sync error, we should still update |  | ||||||
|     ) { |  | ||||||
|         if (remoteEC.entityName === 'blobs' && remoteEntityRow.content !== null) { |         if (remoteEC.entityName === 'blobs' && remoteEntityRow.content !== null) { | ||||||
|             // we always use a Buffer object which is different from normal saving - there we use a simple string type for |             // we always use a Buffer object which is different from normal saving - there we use a simple string type for | ||||||
|             // "string notes". The problem is that in general, it's not possible to detect whether a blob content |             // "string notes". The problem is that in general, it's not possible to detect whether a blob content | ||||||
| @@ -62,7 +61,9 @@ function updateNormalEntity(remoteEC, remoteEntityRow, instanceId) { | |||||||
|  |  | ||||||
|         sql.replace(remoteEC.entityName, remoteEntityRow); |         sql.replace(remoteEC.entityName, remoteEntityRow); | ||||||
|  |  | ||||||
|  |         if (!localEC || localEC.utcDateChanged < remoteEC.utcDateChanged) { | ||||||
|             entityChangesService.putEntityChangeWithInstanceId(remoteEC, instanceId); |             entityChangesService.putEntityChangeWithInstanceId(remoteEC, instanceId); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|     } else if (localEC.hash !== remoteEC.hash && localEC.utcDateChanged > remoteEC.utcDateChanged) { |     } else if (localEC.hash !== remoteEC.hash && localEC.utcDateChanged > remoteEC.utcDateChanged) { | ||||||
|   | |||||||
| @@ -184,10 +184,8 @@ function sortNotesIfNeeded(parentNoteId) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     const sortReversed = parentNote.getLabelValue('sortDirection')?.toLowerCase() === "desc"; |     const sortReversed = parentNote.getLabelValue('sortDirection')?.toLowerCase() === "desc"; | ||||||
|     const sortFoldersFirstLabel = parentNote.getLabel('sortFoldersFirst'); |     const sortFoldersFirst = parentNote.isLabelTruthy('sortFoldersFirst'); | ||||||
|     const sortFoldersFirst = sortFoldersFirstLabel && sortFoldersFirstLabel.value.toLowerCase() !== "false"; |     const sortNatural = parentNote.isLabelTruthy('sortNatural'); | ||||||
|     const sortNaturalLabel = parentNote.getLabel('sortNatural'); |  | ||||||
|     const sortNatural = sortNaturalLabel && sortNaturalLabel.value.toLowerCase() !== "false"; |  | ||||||
|     const sortLocale = parentNote.getLabelValue('sortLocale'); |     const sortLocale = parentNote.getLabelValue('sortLocale'); | ||||||
|  |  | ||||||
|     sortNotes(parentNoteId, sortedLabel.value, sortReversed, sortFoldersFirst, sortNatural, sortLocale); |     sortNotes(parentNoteId, sortedLabel.value, sortReversed, sortFoldersFirst, sortNatural, sortLocale); | ||||||
|   | |||||||
| @@ -7,13 +7,17 @@ Content-Type: application/json | |||||||
|   "parentNoteId": "root", |   "parentNoteId": "root", | ||||||
|   "title": "Hello", |   "title": "Hello", | ||||||
|   "type": "text", |   "type": "text", | ||||||
|   "content": "Hi there!" |   "content": "Hi there!", | ||||||
|  |   "dateCreated": "2023-08-21 23:38:51.123+0200", | ||||||
|  |   "utcDateCreated": "2023-08-21 23:38:51.123Z" | ||||||
| } | } | ||||||
|  |  | ||||||
| > {% | > {% | ||||||
|     client.assert(response.status === 201); |     client.assert(response.status === 201); | ||||||
|     client.assert(response.body.note.noteId.startsWith("forcedId")); |     client.assert(response.body.note.noteId.startsWith("forcedId")); | ||||||
|     client.assert(response.body.note.title == "Hello"); |     client.assert(response.body.note.title == "Hello"); | ||||||
|  |     client.assert(response.body.note.dateCreated == "2023-08-21 23:38:51.123+0200"); | ||||||
|  |     client.assert(response.body.note.utcDateCreated == "2023-08-21 23:38:51.123Z"); | ||||||
|     client.assert(response.body.branch.parentNoteId == "root"); |     client.assert(response.body.branch.parentNoteId == "root"); | ||||||
|  |  | ||||||
|     client.log(`Created note ` + response.body.note.noteId + ` and branch ` + response.body.branch.branchId); |     client.log(`Created note ` + response.body.note.noteId + ` and branch ` + response.body.branch.branchId); | ||||||
|   | |||||||
| @@ -33,7 +33,9 @@ Content-Type: application/json | |||||||
| { | { | ||||||
|   "title": "Wassup", |   "title": "Wassup", | ||||||
|   "type": "html", |   "type": "html", | ||||||
|   "mime": "text/html" |   "mime": "text/html", | ||||||
|  |   "dateCreated": "2023-08-21 23:38:51.123+0200", | ||||||
|  |   "utcDateCreated": "2023-08-21 23:38:51.123Z" | ||||||
| } | } | ||||||
|  |  | ||||||
| ### | ### | ||||||
| @@ -46,6 +48,8 @@ client.assert(response.status === 200); | |||||||
| client.assert(response.body.title === 'Wassup'); | client.assert(response.body.title === 'Wassup'); | ||||||
| client.assert(response.body.type === 'html'); | client.assert(response.body.type === 'html'); | ||||||
| client.assert(response.body.mime === 'text/html'); | client.assert(response.body.mime === 'text/html'); | ||||||
|  | client.assert(response.body.dateCreated == "2023-08-21 23:38:51.123+0200"); | ||||||
|  | client.assert(response.body.utcDateCreated == "2023-08-21 23:38:51.123Z"); | ||||||
| %} | %} | ||||||
|  |  | ||||||
| ### | ### | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user