2018-12-22 22:16:32 +01:00
import server from '../services/server.js' ;
2020-05-02 18:19:41 +02:00
import noteAttributeCache from "../services/note_attribute_cache.js" ;
2021-02-13 20:07:08 +01:00
import ws from "../services/ws.js" ;
import options from "../services/options.js" ;
2021-04-16 23:01:56 +02:00
import froca from "../services/froca.js" ;
2022-07-28 23:59:41 +02:00
import protectedSessionHolder from "../services/protected_session_holder.js" ;
2022-09-25 14:19:30 +02:00
import cssClassManager from "../services/css_class_manager.js" ;
2018-12-22 22:16:32 +01:00
const LABEL = 'label' ;
const RELATION = 'relation' ;
2020-10-14 23:14:04 +02:00
const NOTE _TYPE _ICONS = {
"file" : "bx bx-file" ,
"image" : "bx bx-image" ,
"code" : "bx bx-code" ,
"render" : "bx bx-extension" ,
"search" : "bx bx-file-find" ,
"relation-map" : "bx bx-map-alt" ,
2021-09-20 22:19:47 +02:00
"book" : "bx bx-book" ,
2021-09-29 21:54:56 +02:00
"note-map" : "bx bx-map-alt" ,
2021-11-25 13:47:56 +01:00
"mermaid" : "bx bx-selection" ,
2022-05-28 22:19:29 +02:00
"canvas" : "bx bx-pen" ,
2022-08-06 15:00:56 +02:00
"web-view" : "bx bx-globe-alt" ,
2022-12-01 10:16:57 +01:00
"launcher" : "bx bx-link" ,
2022-12-06 16:23:30 +01:00
"doc" : "bx bxs-file-doc" ,
"content-widget" : "bx bxs-widget"
2020-10-14 23:14:04 +02:00
} ;
2018-08-23 12:55:45 +02:00
/ * *
2020-05-03 13:15:08 +02:00
* FIXME : since there ' s no "full note" anymore we can rename this to Note
*
2021-04-16 22:57:37 +02:00
* This note ' s representation is used in note tree and is kept in Froca .
2018-08-23 12:55:45 +02:00
* /
2018-03-25 12:29:00 -04:00
class NoteShort {
2019-10-26 09:51:08 +02:00
/ * *
2021-04-16 22:57:37 +02:00
* @ param { Froca } froca
2019-10-26 09:51:08 +02:00
* @ param { Object . < string , Object > } row
* /
2021-04-16 22:57:37 +02:00
constructor ( froca , row ) {
this . froca = froca ;
2020-01-29 22:32:22 +01:00
2020-01-30 22:38:31 +01:00
/** @type {string[]} */
this . attributes = [ ] ;
/** @type {string[]} */
this . targetRelations = [ ] ;
/** @type {string[]} */
this . parents = [ ] ;
/** @type {string[]} */
this . children = [ ] ;
/** @type {Object.<string, string>} */
this . parentToBranch = { } ;
/** @type {Object.<string, string>} */
this . childToBranch = { } ;
2020-01-31 20:52:31 +01:00
this . update ( row ) ;
2020-01-29 22:32:22 +01:00
}
2020-01-31 20:52:31 +01:00
update ( row ) {
2021-10-29 21:37:12 +02:00
/** @type {string} */
2018-03-25 12:29:00 -04:00
this . noteId = row . noteId ;
2021-10-29 21:37:12 +02:00
/** @type {string} */
2018-03-25 12:29:00 -04:00
this . title = row . title ;
2021-10-29 21:37:12 +02:00
/** @type {boolean} */
2020-03-08 09:38:49 +01:00
this . isProtected = ! ! row . isProtected ;
2021-11-10 21:30:54 +01:00
/ * *
* one of 'text' , 'code' , 'file' or 'render'
* @ type { string }
* /
2018-03-25 12:29:00 -04:00
this . type = row . type ;
2021-11-10 21:30:54 +01:00
/ * *
* content - type , e . g . "application/json"
* @ type { string }
* /
2018-03-25 12:29:00 -04:00
this . mime = row . mime ;
2019-10-26 09:51:08 +02:00
}
addParent ( parentNoteId , branchId ) {
2020-08-28 14:29:20 +02:00
if ( parentNoteId === 'none' ) {
return ;
}
2019-10-26 09:51:08 +02:00
if ( ! this . parents . includes ( parentNoteId ) ) {
this . parents . push ( parentNoteId ) ;
}
this . parentToBranch [ parentNoteId ] = branchId ;
}
2020-12-10 16:10:10 +01:00
addChild ( childNoteId , branchId , sort = true ) {
2020-12-14 22:12:26 +01:00
if ( ! ( childNoteId in this . childToBranch ) ) {
2019-10-26 09:51:08 +02:00
this . children . push ( childNoteId ) ;
}
this . childToBranch [ childNoteId ] = branchId ;
2020-12-10 16:10:10 +01:00
if ( sort ) {
this . sortChildren ( ) ;
}
2020-09-14 22:48:20 +02:00
}
sortChildren ( ) {
2019-10-26 09:51:08 +02:00
const branchIdPos = { } ;
for ( const branchId of Object . values ( this . childToBranch ) ) {
2021-04-16 22:57:37 +02:00
branchIdPos [ branchId ] = this . froca . getBranch ( branchId ) . notePosition ;
2019-10-26 09:51:08 +02:00
}
this . children . sort ( ( a , b ) => branchIdPos [ this . childToBranch [ a ] ] < branchIdPos [ this . childToBranch [ b ] ] ? - 1 : 1 ) ;
2018-03-25 12:29:00 -04:00
}
2018-08-23 12:55:45 +02:00
/** @returns {boolean} */
2018-03-25 23:25:17 -04:00
isJson ( ) {
return this . mime === "application/json" ;
}
2019-09-06 23:36:08 +02:00
async getContent ( ) {
2021-04-16 22:57:37 +02:00
// we're not caching content since these objects are in froca and as such pretty long lived
2019-09-06 23:36:08 +02:00
const note = await server . get ( "notes/" + this . noteId ) ;
return note . content ;
}
async getJsonContent ( ) {
const content = await this . getContent ( ) ;
try {
return JSON . parse ( content ) ;
}
catch ( e ) {
2022-04-19 23:36:21 +02:00
console . log ( ` Cannot parse content of note ' ${ this . noteId } ': ` , e . message ) ;
2019-09-06 23:36:08 +02:00
return null ;
}
}
2021-12-20 17:30:47 +01:00
/ * *
* @ returns { string [ ] }
* /
getParentBranchIds ( ) {
2020-02-03 20:07:34 +01:00
return Object . values ( this . parentToBranch ) ;
}
2021-12-20 17:30:47 +01:00
/ * *
* @ returns { string [ ] }
* @ deprecated use getParentBranchIds ( ) instead
* /
getBranchIds ( ) {
return this . getParentBranchIds ( ) ;
}
/ * *
* @ returns { Branch [ ] }
* /
getParentBranches ( ) {
2019-10-26 09:51:08 +02:00
const branchIds = Object . values ( this . parentToBranch ) ;
2018-03-25 12:29:00 -04:00
2021-04-16 22:57:37 +02:00
return this . froca . getBranches ( branchIds ) ;
2018-03-25 12:29:00 -04:00
}
2021-12-20 17:30:47 +01:00
/ * *
* @ returns { Branch [ ] }
* @ deprecated use getParentBranches ( ) instead
* /
getBranches ( ) {
return this . getParentBranches ( ) ;
}
2018-08-23 12:55:45 +02:00
/** @returns {boolean} */
2018-04-16 20:40:18 -04:00
hasChildren ( ) {
2019-10-26 09:51:08 +02:00
return this . children . length > 0 ;
2018-04-16 20:40:18 -04:00
}
2020-03-18 22:35:54 +01:00
/** @returns {Branch[]} */
getChildBranches ( ) {
2019-10-27 22:39:38 +01:00
// don't use Object.values() to guarantee order
const branchIds = this . children . map ( childNoteId => this . childToBranch [ childNoteId ] ) ;
2018-03-25 12:29:00 -04:00
2021-04-16 22:57:37 +02:00
return this . froca . getBranches ( branchIds ) ;
2018-03-25 12:29:00 -04:00
}
2018-08-23 15:33:19 +02:00
/** @returns {string[]} */
2018-04-16 23:34:56 -04:00
getParentNoteIds ( ) {
2019-10-26 09:51:08 +02:00
return this . parents ;
2018-04-16 20:40:18 -04:00
}
2020-03-18 22:35:54 +01:00
/** @returns {NoteShort[]} */
getParentNotes ( ) {
2021-04-16 22:57:37 +02:00
return this . froca . getNotesFromCache ( this . parents ) ;
2018-04-16 23:34:56 -04:00
}
2021-02-24 22:38:26 +01:00
// will sort the parents so that non-search & non-archived are first and archived at the end
// this is done so that non-search & non-archived paths are always explored as first when looking for note path
resortParents ( ) {
this . parents . sort ( ( aNoteId , bNoteId ) => {
const aBranchId = this . parentToBranch [ aNoteId ] ;
if ( aBranchId && aBranchId . startsWith ( 'virt-' ) ) {
return 1 ;
}
2021-04-16 22:57:37 +02:00
const aNote = this . froca . getNoteFromCache ( [ aNoteId ] ) ;
2021-02-24 22:38:26 +01:00
if ( aNote . hasLabel ( 'archived' ) ) {
return 1 ;
}
return - 1 ;
} ) ;
}
2018-08-23 15:33:19 +02:00
/** @returns {string[]} */
2018-04-16 23:34:56 -04:00
getChildNoteIds ( ) {
2019-10-26 09:51:08 +02:00
return this . children ;
2018-03-25 12:29:00 -04:00
}
2018-08-23 15:33:19 +02:00
/** @returns {Promise<NoteShort[]>} */
2018-03-25 12:29:00 -04:00
async getChildNotes ( ) {
2021-04-16 22:57:37 +02:00
return await this . froca . getNotes ( this . children ) ;
2018-03-25 12:29:00 -04:00
}
2020-01-25 13:27:23 +01:00
/ * *
* @ param { string } [ type ] - ( optional ) attribute type to filter
* @ param { string } [ name ] - ( optional ) attribute name to filter
* @ returns { Attribute [ ] } all note ' s attributes , including inherited ones
* /
getOwnedAttributes ( type , name ) {
const attrs = this . attributes
2021-04-16 22:57:37 +02:00
. map ( attributeId => this . froca . attributes [ attributeId ] )
2020-05-02 18:19:41 +02:00
. filter ( Boolean ) ; // filter out nulls;
2020-01-25 13:27:23 +01:00
2020-05-02 18:19:41 +02:00
return this . _ _filterAttrs ( attrs , type , name ) ;
2020-01-25 13:27:23 +01:00
}
2018-12-22 22:16:32 +01:00
/ * *
2019-12-01 12:22:22 +01:00
* @ param { string } [ type ] - ( optional ) attribute type to filter
* @ param { string } [ name ] - ( optional ) attribute name to filter
2020-03-18 22:35:54 +01:00
* @ returns { Attribute [ ] } all note ' s attributes , including inherited ones
2018-12-22 22:16:32 +01:00
* /
2020-03-18 22:35:54 +01:00
getAttributes ( type , name ) {
2020-06-04 12:27:41 +02:00
return this . _ _filterAttrs ( this . _ _getCachedAttributes ( [ ] ) , type , name ) ;
}
_ _getCachedAttributes ( path ) {
// notes/clones cannot form tree cycles, it is possible to create attribute inheritance cycle via templates
// when template instance is a parent of template itself
if ( path . includes ( this . noteId ) ) {
return [ ] ;
}
2020-06-27 00:40:35 +02:00
if ( ! ( this . noteId in noteAttributeCache . attributes ) ) {
2020-06-04 12:27:41 +02:00
const newPath = [ ... path , this . noteId ] ;
2020-06-27 00:40:35 +02:00
const attrArrs = [ this . getOwnedAttributes ( ) ] ;
2020-01-25 13:27:23 +01:00
2020-05-02 18:19:41 +02:00
if ( this . noteId !== 'root' ) {
for ( const parentNote of this . getParentNotes ( ) ) {
2021-04-16 22:57:37 +02:00
// these virtual parent-child relationships are also loaded into froca
2020-05-02 18:19:41 +02:00
if ( parentNote . type !== 'search' ) {
2020-06-04 12:27:41 +02:00
attrArrs . push ( parentNote . _ _getInheritableAttributes ( newPath ) ) ;
2020-05-02 18:19:41 +02:00
}
2020-03-29 20:37:40 +02:00
}
2020-01-25 13:27:23 +01:00
}
2020-06-27 00:40:35 +02:00
for ( const templateAttr of attrArrs . flat ( ) . filter ( attr => attr . type === 'relation' && attr . name === 'template' ) ) {
2021-04-16 22:57:37 +02:00
const templateNote = this . froca . notes [ templateAttr . value ] ;
2020-06-27 00:40:35 +02:00
if ( templateNote && templateNote . noteId !== this . noteId ) {
2022-06-19 11:36:29 +02:00
attrArrs . push (
templateNote . _ _getCachedAttributes ( newPath )
// template attr is used as a marker for templates, but it's not meant to be inherited
2022-09-16 23:03:02 +02:00
. filter ( attr => ! ( attr . type === 'label' && ( attr . name === 'template' || attr . name === 'workspacetemplate' ) ) )
2022-06-19 11:36:29 +02:00
) ;
2020-06-27 00:40:35 +02:00
}
}
2020-09-30 22:34:18 +02:00
noteAttributeCache . attributes [ this . noteId ] = [ ] ;
const addedAttributeIds = new Set ( ) ;
for ( const attr of attrArrs . flat ( ) ) {
if ( ! addedAttributeIds . has ( attr . attributeId ) ) {
addedAttributeIds . add ( attr . attributeId ) ;
noteAttributeCache . attributes [ this . noteId ] . push ( attr ) ;
}
}
2020-05-02 18:19:41 +02:00
}
2020-01-25 13:27:23 +01:00
2020-06-04 12:27:41 +02:00
return noteAttributeCache . attributes [ this . noteId ] ;
2020-01-25 13:27:23 +01:00
}
2021-07-20 13:29:11 +02:00
isRoot ( ) {
return this . noted
}
2021-03-10 22:54:55 +01:00
getAllNotePaths ( encounteredNoteIds = null ) {
2021-03-06 20:23:29 +01:00
if ( this . noteId === 'root' ) {
return [ [ 'root' ] ] ;
}
2021-03-10 22:54:55 +01:00
if ( ! encounteredNoteIds ) {
encounteredNoteIds = new Set ( ) ;
}
encounteredNoteIds . add ( this . noteId ) ;
2021-03-06 20:23:29 +01:00
const parentNotes = this . getParentNotes ( ) ;
let paths ;
if ( parentNotes . length === 1 ) { // optimization for the most common case
2021-03-10 22:54:55 +01:00
if ( encounteredNoteIds . has ( parentNotes [ 0 ] . noteId ) ) {
return [ ] ;
}
else {
paths = parentNotes [ 0 ] . getAllNotePaths ( encounteredNoteIds ) ;
}
2021-03-06 20:23:29 +01:00
}
else {
paths = [ ] ;
for ( const parentNote of parentNotes ) {
2021-03-10 22:54:55 +01:00
if ( encounteredNoteIds . has ( parentNote . noteId ) ) {
continue ;
}
const newSet = new Set ( encounteredNoteIds ) ;
paths . push ( ... parentNote . getAllNotePaths ( newSet ) ) ;
2021-03-06 20:23:29 +01:00
}
}
for ( const path of paths ) {
path . push ( this . noteId ) ;
}
return paths ;
}
2021-03-08 00:04:43 +01:00
getSortedNotePaths ( hoistedNotePath = 'root' ) {
const notePaths = this . getAllNotePaths ( ) . map ( path => ( {
notePath : path ,
isInHoistedSubTree : path . includes ( hoistedNotePath ) ,
2021-04-16 22:57:37 +02:00
isArchived : path . find ( noteId => froca . notes [ noteId ] . hasLabel ( 'archived' ) ) ,
2021-06-06 11:13:17 +02:00
isSearch : path . find ( noteId => froca . notes [ noteId ] . type === 'search' ) ,
isHidden : path . includes ( "hidden" )
2021-03-08 00:04:43 +01:00
} ) ) ;
notePaths . sort ( ( a , b ) => {
if ( a . isInHoistedSubTree !== b . isInHoistedSubTree ) {
return a . isInHoistedSubTree ? - 1 : 1 ;
} else if ( a . isSearch !== b . isSearch ) {
return a . isSearch ? 1 : - 1 ;
} else if ( a . isArchived !== b . isArchived ) {
return a . isArchived ? 1 : - 1 ;
} else {
return a . notePath . length - b . notePath . length ;
}
} ) ;
2021-03-08 22:04:52 +01:00
return notePaths ;
2021-03-08 00:04:43 +01:00
}
2020-01-25 13:27:23 +01:00
_ _filterAttrs ( attributes , type , name ) {
2020-05-02 18:19:41 +02:00
if ( ! type && ! name ) {
return attributes ;
} else if ( type && name ) {
2020-01-25 13:27:23 +01:00
return attributes . filter ( attr => attr . type === type && attr . name === name ) ;
} else if ( type ) {
return attributes . filter ( attr => attr . type === type ) ;
} else if ( name ) {
return attributes . filter ( attr => attr . name === name ) ;
2018-12-22 22:16:32 +01:00
}
}
2020-06-04 12:27:41 +02:00
_ _getInheritableAttributes ( path ) {
const attrs = this . _ _getCachedAttributes ( path ) ;
2020-01-25 13:27:23 +01:00
return attrs . filter ( attr => attr . isInheritable ) ;
}
/ * *
* @ param { string } [ name ] - label name to filter
* @ returns { Attribute [ ] } all note ' s labels ( attributes with type label ) , including inherited ones
* /
getOwnedLabels ( name ) {
return this . getOwnedAttributes ( LABEL , name ) ;
}
2018-12-22 22:16:32 +01:00
/ * *
* @ param { string } [ name ] - label name to filter
2020-03-18 22:35:54 +01:00
* @ returns { Attribute [ ] } all note ' s labels ( attributes with type label ) , including inherited ones
2018-12-22 22:16:32 +01:00
* /
2020-03-18 22:35:54 +01:00
getLabels ( name ) {
return this . getAttributes ( LABEL , name ) ;
2018-12-22 22:16:32 +01:00
}
2021-02-13 20:07:08 +01:00
getIcon ( ) {
2020-11-25 20:25:55 +01:00
const iconClassLabels = this . getLabels ( 'iconClass' ) ;
const workspaceIconClass = this . getWorkspaceIconClass ( ) ;
2020-10-14 23:14:04 +02:00
2020-11-25 20:25:55 +01:00
if ( iconClassLabels . length > 0 ) {
2021-03-25 19:46:10 +01:00
return iconClassLabels [ 0 ] . value ;
2020-11-25 20:25:55 +01:00
}
else if ( workspaceIconClass ) {
return workspaceIconClass ;
2020-10-14 23:14:04 +02:00
}
else if ( this . noteId === 'root' ) {
return "bx bx-chevrons-right" ;
}
2021-12-22 16:02:36 +01:00
if ( this . noteId === 'share' ) {
return "bx bx-share-alt" ;
}
2020-10-14 23:14:04 +02:00
else if ( this . type === 'text' ) {
2021-02-13 20:07:08 +01:00
if ( this . isFolder ( ) ) {
2020-10-14 23:14:04 +02:00
return "bx bx-folder" ;
}
else {
return "bx bx-note" ;
}
}
else if ( this . type === 'code' && this . mime . startsWith ( 'text/x-sql' ) ) {
return "bx bx-data" ;
}
else {
return NOTE _TYPE _ICONS [ this . type ] ;
}
}
2022-09-25 14:19:30 +02:00
getColorClass ( ) {
const color = this . getLabelValue ( "color" ) ;
return cssClassManager . createClassForColor ( color ) ;
}
2021-02-13 20:07:08 +01:00
isFolder ( ) {
return this . type === 'search'
|| this . getFilteredChildBranches ( ) . length > 0 ;
}
getFilteredChildBranches ( ) {
let childBranches = this . getChildBranches ( ) ;
if ( ! childBranches ) {
ws . logError ( ` No children for ${ parentNote } . This shouldn't happen. ` ) ;
return ;
}
if ( options . is ( "hideIncludedImages_main" ) ) {
const imageLinks = this . getRelations ( 'imageLink' ) ;
// image is already visible in the parent note so no need to display it separately in the book
childBranches = childBranches . filter ( branch => ! imageLinks . find ( rel => rel . value === branch . noteId ) ) ;
}
// we're not checking hideArchivedNotes since that would mean we need to lazy load the child notes
// which would seriously slow down everything.
// we check this flag only once user chooses to expand the parent. This has the negative consequence that
// note may appear as folder but not contain any children when all of them are archived
return childBranches ;
}
2020-01-25 13:27:23 +01:00
/ * *
* @ param { string } [ name ] - relation name to filter
* @ returns { Attribute [ ] } all note ' s relations ( attributes with type relation ) , including inherited ones
* /
getOwnedRelations ( name ) {
return this . getOwnedAttributes ( RELATION , name ) ;
}
2018-12-22 22:16:32 +01:00
/ * *
* @ param { string } [ name ] - relation name to filter
2020-03-18 22:35:54 +01:00
* @ returns { Attribute [ ] } all note ' s relations ( attributes with type relation ) , including inherited ones
2018-12-22 22:16:32 +01:00
* /
2020-03-18 22:35:54 +01:00
getRelations ( name ) {
return this . getAttributes ( RELATION , name ) ;
2018-12-22 22:16:32 +01:00
}
/ * *
* @ param { string } type - attribute type ( label , relation , etc . )
* @ param { string } name - attribute name
2020-03-18 22:35:54 +01:00
* @ returns { boolean } true if note has an attribute with given type and name ( including inherited )
2018-12-22 22:16:32 +01:00
* /
2020-03-18 22:35:54 +01:00
hasAttribute ( type , name ) {
return ! ! this . getAttribute ( type , name ) ;
2018-12-22 22:16:32 +01:00
}
2020-01-25 13:27:23 +01:00
/ * *
* @ param { string } type - attribute type ( label , relation , etc . )
* @ param { string } name - attribute name
* @ returns { boolean } true if note has an attribute with given type and name ( including inherited )
* /
hasOwnedAttribute ( type , name ) {
return ! ! this . getOwnedAttribute ( type , name ) ;
}
/ * *
* @ param { string } type - attribute type ( label , relation , etc . )
* @ param { string } name - attribute name
* @ returns { Attribute } attribute of given type and name . If there 's more such attributes, first is returned. Returns null if there' s no such attribute belonging to this note .
* /
getOwnedAttribute ( type , name ) {
const attributes = this . getOwnedAttributes ( type , name ) ;
return attributes . length > 0 ? attributes [ 0 ] : 0 ;
}
2018-12-22 22:16:32 +01:00
/ * *
* @ param { string } type - attribute type ( label , relation , etc . )
* @ param { string } name - attribute name
2020-03-18 22:35:54 +01:00
* @ returns { Attribute } attribute of given type and name . If there 's more such attributes, first is returned. Returns null if there' s no such attribute belonging to this note .
2018-12-22 22:16:32 +01:00
* /
2020-03-18 22:35:54 +01:00
getAttribute ( type , name ) {
const attributes = this . getAttributes ( type , name ) ;
2020-01-25 13:27:23 +01:00
2020-10-08 22:08:58 +02:00
return attributes . length > 0 ? attributes [ 0 ] : null ;
2020-01-25 13:27:23 +01:00
}
/ * *
* @ param { string } type - attribute type ( label , relation , etc . )
* @ param { string } name - attribute name
* @ returns { string } attribute value of given type and name or null if no such attribute exists .
* /
getOwnedAttributeValue ( type , name ) {
const attr = this . getOwnedAttribute ( type , name ) ;
2018-12-22 22:16:32 +01:00
2020-01-25 13:27:23 +01:00
return attr ? attr . value : null ;
2018-12-22 22:16:32 +01:00
}
/ * *
* @ param { string } type - attribute type ( label , relation , etc . )
* @ param { string } name - attribute name
2020-03-18 22:35:54 +01:00
* @ returns { string } attribute value of given type and name or null if no such attribute exists .
2018-12-22 22:16:32 +01:00
* /
2020-03-18 22:35:54 +01:00
getAttributeValue ( type , name ) {
const attr = this . getAttribute ( type , name ) ;
2018-12-22 22:16:32 +01:00
return attr ? attr . value : null ;
}
2020-01-25 13:27:23 +01:00
/ * *
* @ param { string } name - label name
* @ returns { boolean } true if label exists ( excluding inherited )
* /
hasOwnedLabel ( name ) { return this . hasOwnedAttribute ( LABEL , name ) ; }
2018-12-22 22:16:32 +01:00
/ * *
* @ param { string } name - label name
2020-03-18 22:35:54 +01:00
* @ returns { boolean } true if label exists ( including inherited )
2018-12-22 22:16:32 +01:00
* /
2020-03-18 22:35:54 +01:00
hasLabel ( name ) { return this . hasAttribute ( LABEL , name ) ; }
2018-12-22 22:16:32 +01:00
2020-01-25 13:27:23 +01:00
/ * *
* @ param { string } name - relation name
* @ returns { boolean } true if relation exists ( excluding inherited )
* /
hasOwnedRelation ( name ) { return this . hasOwnedAttribute ( RELATION , name ) ; }
2018-12-22 22:16:32 +01:00
/ * *
* @ param { string } name - relation name
2020-03-18 22:35:54 +01:00
* @ returns { boolean } true if relation exists ( including inherited )
2018-12-22 22:16:32 +01:00
* /
2020-03-18 22:35:54 +01:00
hasRelation ( name ) { return this . hasAttribute ( RELATION , name ) ; }
2018-12-22 22:16:32 +01:00
2020-01-25 13:27:23 +01:00
/ * *
* @ param { string } name - label name
* @ returns { Attribute } label if it exists , null otherwise
* /
getOwnedLabel ( name ) { return this . getOwnedAttribute ( LABEL , name ) ; }
2018-12-22 22:16:32 +01:00
/ * *
* @ param { string } name - label name
2020-03-18 22:35:54 +01:00
* @ returns { Attribute } label if it exists , null otherwise
2018-12-22 22:16:32 +01:00
* /
2020-03-18 22:35:54 +01:00
getLabel ( name ) { return this . getAttribute ( LABEL , name ) ; }
2018-12-22 22:16:32 +01:00
2020-01-25 13:27:23 +01:00
/ * *
* @ param { string } name - relation name
* @ returns { Attribute } relation if it exists , null otherwise
* /
getOwnedRelation ( name ) { return this . getOwnedAttribute ( RELATION , name ) ; }
2018-12-22 22:16:32 +01:00
/ * *
* @ param { string } name - relation name
2020-03-18 22:35:54 +01:00
* @ returns { Attribute } relation if it exists , null otherwise
2018-12-22 22:16:32 +01:00
* /
2020-03-18 22:35:54 +01:00
getRelation ( name ) { return this . getAttribute ( RELATION , name ) ; }
2018-12-22 22:16:32 +01:00
2020-01-25 13:27:23 +01:00
/ * *
* @ param { string } name - label name
* @ returns { string } label value if label exists , null otherwise
* /
getOwnedLabelValue ( name ) { return this . getOwnedAttributeValue ( LABEL , name ) ; }
2018-12-22 22:16:32 +01:00
/ * *
* @ param { string } name - label name
2020-03-18 22:35:54 +01:00
* @ returns { string } label value if label exists , null otherwise
2018-12-22 22:16:32 +01:00
* /
2020-03-18 22:35:54 +01:00
getLabelValue ( name ) { return this . getAttributeValue ( LABEL , name ) ; }
2018-12-22 22:16:32 +01:00
2020-01-25 13:27:23 +01:00
/ * *
* @ param { string } name - relation name
* @ returns { string } relation value if relation exists , null otherwise
* /
getOwnedRelationValue ( name ) { return this . getOwnedAttributeValue ( RELATION , name ) ; }
2018-12-22 22:16:32 +01:00
/ * *
* @ param { string } name - relation name
2020-03-18 22:35:54 +01:00
* @ returns { string } relation value if relation exists , null otherwise
2018-12-22 22:16:32 +01:00
* /
2020-03-18 22:35:54 +01:00
getRelationValue ( name ) { return this . getAttributeValue ( RELATION , name ) ; }
2018-12-22 22:16:32 +01:00
/ * *
* @ param { string } name
2019-08-17 11:28:36 +02:00
* @ returns { Promise < NoteShort > | null } target note of the relation or null ( if target is empty or note was not found )
2018-12-22 22:16:32 +01:00
* /
async getRelationTarget ( name ) {
2019-08-17 11:28:36 +02:00
const targets = await this . getRelationTargets ( name ) ;
2018-12-22 22:16:32 +01:00
2019-08-17 11:28:36 +02:00
return targets . length > 0 ? targets [ 0 ] : null ;
}
/ * *
* @ param { string } [ name ] - relation name to filter
* @ returns { Promise < NoteShort [ ] > }
* /
async getRelationTargets ( name ) {
2020-03-18 22:42:29 +01:00
const relations = this . getRelations ( name ) ;
2019-08-17 11:28:36 +02:00
const targets = [ ] ;
for ( const relation of relations ) {
2021-04-16 22:57:37 +02:00
targets . push ( await this . froca . getNote ( relation . value ) ) ;
2019-08-17 11:28:36 +02:00
}
return targets ;
2018-12-22 22:16:32 +01:00
}
2020-06-09 22:59:22 +02:00
/ * *
* @ returns { NoteShort [ ] }
* /
getTemplateNotes ( ) {
const relations = this . getRelations ( 'template' ) ;
2021-04-16 22:57:37 +02:00
return relations . map ( rel => this . froca . notes [ rel . value ] ) ;
2020-06-09 22:59:22 +02:00
}
2021-01-23 21:41:02 +01:00
getPromotedDefinitionAttributes ( ) {
if ( this . hasLabel ( 'hidePromotedAttributes' ) ) {
return [ ] ;
}
2022-06-19 12:18:13 +02:00
const promotedAttrs = this . getAttributes ( )
2021-01-23 21:41:02 +01:00
. filter ( attr => attr . isDefinition ( ) )
. filter ( attr => {
const def = attr . getDefinition ( ) ;
return def && def . isPromoted ;
} ) ;
2022-06-19 12:18:13 +02:00
// attrs are not resorted if position changes after initial load
promotedAttrs . sort ( ( a , b ) => a . position < b . position ? - 1 : 1 ) ;
return promotedAttrs ;
2021-01-23 21:41:02 +01:00
}
2021-12-20 17:30:47 +01:00
hasAncestor ( ancestorNoteId , visitedNoteIds = null ) {
if ( this . noteId === ancestorNoteId ) {
2020-06-09 22:59:22 +02:00
return true ;
}
2021-02-09 20:15:14 +01:00
if ( ! visitedNoteIds ) {
visitedNoteIds = new Set ( ) ;
} else if ( visitedNoteIds . has ( this . noteId ) ) {
// to avoid infinite cycle when template is descendent of the instance
return false ;
}
visitedNoteIds . add ( this . noteId ) ;
2020-06-09 22:59:22 +02:00
for ( const templateNote of this . getTemplateNotes ( ) ) {
2021-12-20 17:30:47 +01:00
if ( templateNote . hasAncestor ( ancestorNoteId , visitedNoteIds ) ) {
2020-06-09 22:59:22 +02:00
return true ;
}
}
for ( const parentNote of this . getParentNotes ( ) ) {
2021-12-20 17:30:47 +01:00
if ( parentNote . hasAncestor ( ancestorNoteId , visitedNoteIds ) ) {
2020-06-09 22:59:22 +02:00
return true ;
}
}
return false ;
}
2018-12-22 22:16:32 +01:00
/ * *
2021-10-27 22:28:33 +02:00
* @ deprecated NOOP
2018-12-22 22:16:32 +01:00
* /
2021-10-27 22:28:33 +02:00
invalidateAttributeCache ( ) { }
2018-12-22 22:16:32 +01:00
2019-08-19 20:12:00 +02:00
/ * *
2019-08-19 20:59:40 +02:00
* Get relations which target this note
*
2020-01-25 13:27:23 +01:00
* @ returns { Attribute [ ] }
2019-08-19 20:12:00 +02:00
* /
2020-01-25 13:27:23 +01:00
getTargetRelations ( ) {
return this . targetRelations
2021-04-16 22:57:37 +02:00
. map ( attributeId => this . froca . attributes [ attributeId ] ) ;
2019-08-19 20:12:00 +02:00
}
2020-09-05 22:45:26 +02:00
/ * *
* Get relations which target this note
*
* @ returns { NoteShort [ ] }
* /
async getTargetRelationSourceNotes ( ) {
const targetRelations = this . getTargetRelations ( ) ;
2021-04-16 22:57:37 +02:00
return await this . froca . getNotes ( targetRelations . map ( tr => tr . noteId ) ) ;
2020-09-05 22:45:26 +02:00
}
2020-06-14 14:30:57 +02:00
/ * *
* Return note complement which is most importantly note ' s content
*
* @ return { Promise < NoteComplement > }
* /
async getNoteComplement ( ) {
2021-04-16 22:57:37 +02:00
return await this . froca . getNoteComplement ( this . noteId ) ;
2020-06-14 14:30:57 +02:00
}
2021-10-29 21:37:12 +02:00
toString ( ) {
2018-03-25 12:29:00 -04:00
return ` Note(noteId= ${ this . noteId } , title= ${ this . title } ) ` ;
}
2018-04-08 08:21:49 -04:00
get dto ( ) {
const dto = Object . assign ( { } , this ) ;
2021-04-16 22:57:37 +02:00
delete dto . froca ;
2018-04-08 08:21:49 -04:00
return dto ;
}
2020-02-25 09:40:49 +01:00
2020-03-18 22:42:29 +01:00
getCssClass ( ) {
const labels = this . getLabels ( 'cssClass' ) ;
2020-02-25 09:40:49 +01:00
return labels . map ( l => l . value ) . join ( ' ' ) ;
}
2020-11-24 23:24:05 +01:00
2020-11-25 20:25:55 +01:00
getWorkspaceIconClass ( ) {
const labels = this . getLabels ( 'workspaceIconClass' ) ;
return labels . length > 0 ? labels [ 0 ] . value : "" ;
}
getWorkspaceTabBackgroundColor ( ) {
const labels = this . getLabels ( 'workspaceTabBackgroundColor' ) ;
return labels . length > 0 ? labels [ 0 ] . value : "" ;
2020-11-24 23:24:05 +01:00
}
2021-05-07 21:23:10 +02:00
/** @returns {boolean} true if this note is JavaScript (code or attachment) */
isJavaScript ( ) {
return ( this . type === "code" || this . type === "file" )
&& ( this . mime . startsWith ( "application/javascript" )
|| this . mime === "application/x-javascript"
|| this . mime === "text/javascript" ) ;
}
/** @returns {boolean} true if this note is HTML */
isHtml ( ) {
return ( this . type === "code" || this . type === "file" || this . type === "render" ) && this . mime === "text/html" ;
}
/** @returns {string|null} JS script environment - either "frontend" or "backend" */
getScriptEnv ( ) {
if ( this . isHtml ( ) || ( this . isJavaScript ( ) && this . mime . endsWith ( 'env=frontend' ) ) ) {
return "frontend" ;
}
if ( this . type === 'render' ) {
return "frontend" ;
}
if ( this . isJavaScript ( ) && this . mime . endsWith ( 'env=backend' ) ) {
return "backend" ;
}
return null ;
}
async executeScript ( ) {
if ( ! this . isJavaScript ( ) ) {
throw new Error ( ` Note ${ this . noteId } is of type ${ this . type } and mime ${ this . mime } and thus cannot be executed ` ) ;
}
const env = this . getScriptEnv ( ) ;
if ( env === "frontend" ) {
const bundleService = ( await import ( "../services/bundle.js" ) ) . default ;
2022-11-27 23:43:25 +01:00
return await bundleService . getAndExecuteBundle ( this . noteId ) ;
2021-05-07 21:23:10 +02:00
}
else if ( env === "backend" ) {
2022-11-27 23:43:25 +01:00
return await server . post ( 'script/run/' + this . noteId ) ;
2021-05-07 21:23:10 +02:00
}
else {
throw new Error ( ` Unrecognized env type ${ env } for note ${ this . noteId } ` ) ;
}
}
2021-12-22 15:01:54 +01:00
isShared ( ) {
for ( const parentNoteId of this . parents ) {
if ( parentNoteId === 'root' || parentNoteId === 'none' ) {
continue ;
}
const parentNote = froca . notes [ parentNoteId ] ;
2022-01-12 19:46:40 +01:00
if ( ! parentNote || parentNote . type === 'search' ) {
2021-12-22 15:01:54 +01:00
continue ;
}
if ( parentNote . noteId === 'share' || parentNote . isShared ( ) ) {
return true ;
}
}
return false ;
}
2022-07-28 23:59:41 +02:00
isContentAvailable ( ) {
return ! this . isProtected || protectedSessionHolder . isProtectedSessionAvailable ( )
}
2022-08-05 19:15:28 +02:00
isLaunchBarConfig ( ) {
2022-12-01 10:16:57 +01:00
return this . type === 'launcher' || this . noteId . startsWith ( "lb_" ) ;
2022-08-05 19:15:28 +02:00
}
2018-03-25 12:29:00 -04:00
}
2020-06-04 12:27:41 +02:00
export default NoteShort ;