2018-08-23 12:55:45 +02:00
import server from './server.js' ;
import utils from './utils.js' ;
2019-10-20 10:00:18 +02:00
import toastService from './toast.js' ;
2018-08-23 12:55:45 +02:00
import linkService from './link.js' ;
2021-04-16 23:01:56 +02:00
import froca from './froca.js' ;
2018-12-22 20:57:09 +01:00
import noteTooltipService from './note_tooltip.js' ;
2019-08-17 11:28:36 +02:00
import protectedSessionService from './protected_session.js' ;
import dateNotesService from './date_notes.js' ;
2021-03-28 00:07:38 +01:00
import searchService from './search.js' ;
2023-01-03 14:31:46 +01:00
import RightPanelWidget from '../widgets/right_panel_widget.js' ;
2019-10-20 17:49:58 +02:00
import ws from "./ws.js" ;
2022-12-01 13:07:23 +01:00
import appContext from "../components/app_context.js" ;
2021-05-22 12:35:41 +02:00
import NoteContextAwareWidget from "../widgets/note_context_aware_widget.js" ;
2020-03-19 17:15:14 +01:00
import BasicWidget from "../widgets/basic_widget.js" ;
2022-09-17 23:06:17 +02:00
import SpacedUpdate from "./spaced_update.js" ;
2022-12-01 00:17:15 +01:00
import shortcutService from "./shortcuts.js" ;
2018-08-23 12:55:45 +02:00
/ * *
2023-01-05 23:38:41 +01:00
* < p > This is the main frontend API interface for scripts . All the properties and methods are published in the "api" object
* available in the JS frontend notes . You can use e . g . < code > api . showMessage ( api . startNote . title ) ; < / c o d e > < / p >
2018-08-23 15:33:19 +02:00
*
2018-08-23 12:55:45 +02:00
* @ constructor
* /
2020-02-25 19:19:10 +01:00
function FrontendScriptApi ( startNote , currentNote , originEntity = null , $container = null ) {
2019-10-05 10:55:29 +02:00
/** @property {jQuery} container of all the rendered script content */
this . $container = $container ;
2018-08-23 12:55:45 +02:00
/** @property {object} note where script started executing */
this . startNote = startNote ;
/** @property {object} note where script is currently executing */
this . currentNote = currentNote ;
/** @property {object|null} entity whose event triggered this execution */
this . originEntity = originEntity ;
2023-01-05 23:38:41 +01:00
/** @property {dayjs} day.js library for date manipulation. See {@link https://day.js.org} for documentation */
2019-04-14 12:18:52 +02:00
this . dayjs = dayjs ;
2023-01-03 14:31:46 +01:00
/** @property {RightPanelWidget} */
this . RightPanelWidget = RightPanelWidget ;
2019-08-17 11:28:36 +02:00
2021-09-30 12:23:22 +02:00
/** @property {NoteContextAwareWidget} */
this . NoteContextAwareWidget = NoteContextAwareWidget ;
2020-03-19 17:15:14 +01:00
/** @property {BasicWidget} */
this . BasicWidget = BasicWidget ;
2018-08-23 12:55:45 +02:00
/ * *
* Activates note in the tree and in the note detail .
*
* @ method
* @ param { string } notePath ( or noteId )
* @ returns { Promise < void > }
* /
2020-02-02 22:04:28 +01:00
this . activateNote = async notePath => {
2021-05-22 12:35:41 +02:00
await appContext . tabManager . getActiveContext ( ) . setNote ( notePath ) ;
2019-07-28 14:47:35 +02:00
} ;
2018-08-23 12:55:45 +02:00
/ * *
2020-01-04 21:53:49 +01:00
* Activates newly created note . Compared to this . activateNote ( ) also makes sure that frontend has been fully synced .
2018-08-23 12:55:45 +02:00
*
* @ param { string } notePath ( or noteId )
2023-01-05 23:38:41 +01:00
* @ returns { Promise < void > }
2018-08-23 12:55:45 +02:00
* /
this . activateNewNote = async notePath => {
2020-08-02 23:27:48 +02:00
await ws . waitForMaxKnownEntityChangeId ( ) ;
2018-08-23 12:55:45 +02:00
2021-05-22 12:35:41 +02:00
await appContext . tabManager . getActiveContext ( ) . setNote ( notePath ) ;
2023-04-05 22:07:08 +02:00
await appContext . triggerEvent ( 'focusAndSelectTitle' ) ;
2018-08-23 12:55:45 +02:00
} ;
2021-02-17 23:55:51 +01:00
/ * *
* Open a note in a new tab .
*
2023-01-05 23:38:41 +01:00
* @ method
2021-02-17 23:55:51 +01:00
* @ param { string } notePath ( or noteId )
* @ param { boolean } activate - set to true to activate the new tab , false to stay on the current tab
2023-01-05 23:38:41 +01:00
* @ returns { Promise < void > }
2021-02-17 23:55:51 +01:00
* /
this . openTabWithNote = async ( notePath , activate ) => {
await ws . waitForMaxKnownEntityChangeId ( ) ;
2023-02-14 16:06:49 +01:00
await appContext . tabManager . openContextWithNote ( notePath , { activate } ) ;
2021-02-17 23:55:51 +01:00
if ( activate ) {
2023-04-05 22:07:08 +02:00
await appContext . triggerEvent ( 'focusAndSelectTitle' ) ;
2021-02-17 23:55:51 +01:00
}
} ;
2022-06-02 17:36:30 +02:00
/ * *
* Open a note in a new split .
*
2023-01-05 23:38:41 +01:00
* @ method
2022-06-02 17:36:30 +02:00
* @ param { string } notePath ( or noteId )
* @ param { boolean } activate - set to true to activate the new split , false to stay on the current split
2023-01-05 23:38:41 +01:00
* @ returns { Promise < void > }
2022-06-02 17:36:30 +02:00
* /
this . openSplitWithNote = async ( notePath , activate ) => {
await ws . waitForMaxKnownEntityChangeId ( ) ;
const subContexts = appContext . tabManager . getActiveContext ( ) . getSubContexts ( ) ;
const { ntxId } = subContexts [ subContexts . length - 1 ] ;
2023-04-05 22:07:08 +02:00
await appContext . triggerCommand ( "openNewNoteSplit" , { ntxId , notePath } ) ;
2022-06-02 17:36:30 +02:00
if ( activate ) {
2023-04-05 22:07:08 +02:00
await appContext . triggerEvent ( 'focusAndSelectTitle' ) ;
2022-06-02 17:36:30 +02:00
}
} ;
2018-08-23 12:55:45 +02:00
/ * *
2022-12-17 21:46:51 +01:00
* Adds a new launcher to the launchbar . If the launcher ( id ) already exists , it will be updated .
*
2023-01-05 23:38:41 +01:00
* @ method
2022-12-17 21:46:51 +01:00
* @ deprecated you can now create / modify launchers in the top - left Menu - > Configure Launchbar
2022-12-22 14:59:20 +01:00
* for special needs there 's also backend API' s createOrUpdateLauncher ( )
2023-01-03 14:31:46 +01:00
* @ param { object } opts
* @ property { string } [ opts . id ] - id of the button , used to identify the old instances of this button to be replaced
* ID is optional because of BC , but not specifying it is deprecated . ID can be alphanumeric only .
* @ property { string } opts . title
* @ property { string } [ opts . icon ] - name of the boxicon to be used ( e . g . "time" for "bx-time" icon )
* @ property { function } opts . action - callback handling the click on the button
* @ property { string } [ opts . shortcut ] - keyboard shortcut for the button , e . g . "alt+t"
2018-08-23 12:55:45 +02:00
* /
2022-12-17 21:46:51 +01:00
this . addButtonToToolbar = async opts => {
console . warn ( "api.addButtonToToolbar() has been deprecated since v0.58 and may be removed in the future. Use Menu -> Configure Launchbar to create/update launchers instead." ) ;
const { action , ... reqBody } = opts ;
reqBody . action = action . toString ( ) ;
await server . put ( 'special-notes/api-script-launcher' , reqBody ) ;
} ;
2018-08-23 12:55:45 +02:00
function prepareParams ( params ) {
if ( ! params ) {
return params ;
}
return params . map ( p => {
if ( typeof p === "function" ) {
2022-12-21 15:19:05 +01:00
return ` !@#Function: ${ p . toString ( ) } ` ;
2018-08-23 12:55:45 +02:00
}
else {
return p ;
}
} ) ;
}
/ * *
2019-12-28 12:55:53 +01:00
* Executes given anonymous function on the backend .
2018-08-23 12:55:45 +02:00
* Internally this serializes the anonymous function into string and sends it to backend via AJAX .
*
2023-01-05 23:38:41 +01:00
* @ method
2018-08-23 12:55:45 +02:00
* @ param { string } script - script to be executed on the backend
2023-01-15 21:04:17 +01:00
* @ param { Array . < ? > } params - list of parameters to the anonymous function to be sent to backend
2023-01-05 23:38:41 +01:00
* @ returns { Promise < * > } return value of the executed function on the backend
2018-08-23 12:55:45 +02:00
* /
2019-12-28 12:55:53 +01:00
this . runOnBackend = async ( script , params = [ ] ) => {
2018-08-23 12:55:45 +02:00
if ( typeof script === "function" ) {
script = script . toString ( ) ;
}
const ret = await server . post ( 'script/exec' , {
script : script ,
params : prepareParams ( params ) ,
startNoteId : startNote . noteId ,
currentNoteId : currentNote . noteId ,
originEntityName : "notes" , // currently there's no other entity on frontend which can trigger event
originEntityId : originEntity ? originEntity . noteId : null
2020-01-28 21:54:28 +01:00
} , "script" ) ;
2018-08-23 12:55:45 +02:00
if ( ret . success ) {
2021-02-22 22:43:54 +01:00
await ws . waitForMaxKnownEntityChangeId ( ) ;
2019-10-20 17:49:58 +02:00
2018-08-23 12:55:45 +02:00
return ret . executionResult ;
}
else {
2022-12-21 15:19:05 +01:00
throw new Error ( ` server error: ${ ret . error } ` ) ;
2018-08-23 12:55:45 +02:00
}
} ;
2019-04-22 22:52:09 +02:00
/ * *
* This is a powerful search method - you can search by attributes and their values , e . g . :
2020-09-18 21:47:59 +02:00
* "#dateModified =* MONTH AND #log" . See full documentation for all options at : https : //github.com/zadam/trilium/wiki/Search
2019-04-22 22:52:09 +02:00
*
* @ method
* @ param { string } searchString
2023-01-03 13:35:10 +01:00
* @ returns { Promise < FNote [ ] > }
2019-04-22 22:52:09 +02:00
* /
this . searchForNotes = async searchString => {
2021-03-28 00:07:38 +01:00
return await searchService . searchForNotes ( searchString ) ;
2019-04-22 22:52:09 +02:00
} ;
/ * *
* This is a powerful search method - you can search by attributes and their values , e . g . :
2020-09-18 21:47:59 +02:00
* "#dateModified =* MONTH AND #log" . See full documentation for all options at : https : //github.com/zadam/trilium/wiki/Search
2019-04-22 22:52:09 +02:00
*
* @ method
* @ param { string } searchString
2023-01-03 13:35:10 +01:00
* @ returns { Promise < FNote | null > }
2019-04-22 22:52:09 +02:00
* /
this . searchForNote = async searchString => {
const notes = await this . searchForNotes ( searchString ) ;
return notes . length > 0 ? notes [ 0 ] : null ;
} ;
2019-04-09 21:13:47 +02:00
/ * *
* Returns note by given noteId . If note is missing from cache , it ' s loaded .
* *
2023-01-05 23:38:41 +01:00
* @ method
2019-04-09 21:13:47 +02:00
* @ param { string } noteId
2023-01-05 23:38:41 +01:00
* @ returns { Promise < FNote > }
2019-04-09 21:13:47 +02:00
* /
2021-04-16 22:57:37 +02:00
this . getNote = async noteId => await froca . getNote ( noteId ) ;
2019-04-09 21:13:47 +02:00
2018-08-23 12:55:45 +02:00
/ * *
* Returns list of notes . If note is missing from cache , it ' s loaded .
*
* This is often used to bulk - fill the cache with notes which would have to be picked one by one
* otherwise ( by e . g . createNoteLink ( ) )
*
2023-01-05 23:38:41 +01:00
* @ method
2018-08-23 15:33:19 +02:00
* @ param { string [ ] } noteIds
2018-08-23 12:55:45 +02:00
* @ param { boolean } [ silentNotFoundError ] - don ' t report error if the note is not found
2023-01-05 23:38:41 +01:00
* @ returns { Promise < FNote [ ] > }
2018-08-23 12:55:45 +02:00
* /
2021-04-16 22:57:37 +02:00
this . getNotes = async ( noteIds , silentNotFoundError = false ) => await froca . getNotes ( noteIds , silentNotFoundError ) ;
2018-08-23 12:55:45 +02:00
2019-04-13 22:56:45 +02:00
/ * *
2019-10-26 10:00:26 +02:00
* Update frontend tree ( note ) cache from the backend .
*
2019-04-13 22:56:45 +02:00
* @ method
2023-01-05 23:38:41 +01:00
* @ param { string [ ] } noteIds
2019-04-13 22:56:45 +02:00
* /
2021-04-16 22:57:37 +02:00
this . reloadNotes = async noteIds => await froca . reloadNotes ( noteIds ) ;
2019-04-13 22:56:45 +02:00
2018-08-23 12:55:45 +02:00
/ * *
* Instance name identifies particular Trilium instance . It can be useful for scripts
* if some action needs to happen on only one specific instance .
*
2023-01-05 23:38:41 +01:00
* @ method
* @ returns { string }
2018-08-23 12:55:45 +02:00
* /
this . getInstanceName = ( ) => window . glob . instanceName ;
/ * *
* @ method
* @ param { Date } date
* @ returns { string } date in YYYY - MM - DD format
* /
this . formatDateISO = utils . formatDateISO ;
/ * *
* @ method
* @ param { string } str
* @ returns { Date } parsed object
* /
this . parseDate = utils . parseDate ;
/ * *
* Show info message to the user .
*
* @ method
* @ param { string } message
* /
2019-10-20 10:00:18 +02:00
this . showMessage = toastService . showMessage ;
2018-08-23 12:55:45 +02:00
/ * *
* Show error message to the user .
*
* @ method
* @ param { string } message
* /
2019-10-20 10:00:18 +02:00
this . showError = toastService . showError ;
2018-08-23 12:55:45 +02:00
2022-05-13 22:33:57 +02:00
/ * *
* Trigger command .
*
* @ method
* @ param { string } name
* @ param { object } data
* /
this . triggerCommand = ( name , data ) => appContext . triggerCommand ( name , data ) ;
/ * *
* Trigger event .
*
* @ method
* @ param { string } name
* @ param { object } data
* /
this . triggerEvent = ( name , data ) => appContext . triggerEvent ( name , data ) ;
2018-08-23 12:55:45 +02:00
/ * *
* Create note link ( jQuery object ) for given note .
*
* @ method
* @ param { string } notePath ( or noteId )
2020-11-17 20:11:10 +01:00
* @ param { object } [ params ]
* @ param { boolean } [ params . showTooltip = true ] - enable / disable tooltip on the link
* @ param { boolean } [ params . showNotePath = false ] - show also whole note ' s path as part of the link
2021-12-01 23:12:54 +01:00
* @ param { boolean } [ params . showNoteIcon = false ] - show also note icon before the title
2022-11-08 10:11:52 +01:00
* @ param { string } [ params . title = ] - custom link tile with note ' s title as default
2018-08-23 12:55:45 +02:00
* /
this . createNoteLink = linkService . createNoteLink ;
2018-09-03 16:05:28 +02:00
2022-05-09 23:13:34 +02:00
/ * *
* Adds given text to the editor cursor
*
* @ method
2023-01-05 23:38:41 +01:00
* @ param { string } text - this must be clear text , HTML is not supported .
2022-05-09 23:13:34 +02:00
* /
this . addTextToActiveContextEditor = text => appContext . triggerCommand ( 'addTextToActiveEditor' , { text } ) ;
2018-09-03 16:05:28 +02:00
/ * *
2019-03-12 21:39:35 +01:00
* @ method
2023-01-03 13:35:10 +01:00
* @ returns { FNote } active note ( loaded into right pane )
2019-03-12 21:39:35 +01:00
* /
2022-05-09 23:13:34 +02:00
this . getActiveContextNote = ( ) => appContext . tabManager . getActiveContextNote ( ) ;
2020-01-10 20:10:17 +01:00
/ * *
* See https : //ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance.
*
* @ method
2022-05-03 23:25:28 +02:00
* @ returns { Promise < CKEditor > } instance of CKEditor
2020-01-10 20:10:17 +01:00
* /
2022-05-17 23:53:35 +02:00
this . getActiveContextTextEditor = ( ) => appContext . tabManager . getActiveContext ( ) ? . getTextEditor ( ) ;
2022-05-03 23:25:28 +02:00
/ * *
* See https : //codemirror.net/doc/manual.html#api
*
* @ method
* @ returns { Promise < CodeMirror > } instance of CodeMirror
* /
2022-05-17 23:53:35 +02:00
this . getActiveContextCodeEditor = ( ) => appContext . tabManager . getActiveContext ( ) ? . getCodeEditor ( ) ;
2022-05-03 23:25:28 +02:00
/ * *
* Get access to the widget handling note detail . Methods like ` getWidgetType() ` and ` getTypeWidget() ` to get to the
* implementation of actual widget type .
*
* @ method
* @ returns { Promise < NoteDetailWidget > }
* /
this . getActiveNoteDetailWidget = ( ) => new Promise ( resolve => appContext . triggerCommand ( 'executeInActiveNoteDetailWidget' , { callback : resolve } ) ) ;
2020-01-10 20:10:17 +01:00
2019-04-09 21:13:47 +02:00
/ * *
* @ method
2019-05-14 22:29:47 +02:00
* @ returns { Promise < string | null > } returns note path of active note or null if there isn ' t active note
2019-04-09 21:13:47 +02:00
* /
2022-05-09 23:13:34 +02:00
this . getActiveContextNotePath = ( ) => appContext . tabManager . getActiveContextNotePath ( ) ;
2019-04-09 21:13:47 +02:00
2022-05-03 23:25:28 +02:00
/ * *
* Returns component which owns given DOM element ( the nearest parent component in DOM tree )
*
* @ method
* @ param { Element } el - DOM element
* @ returns { Component }
* /
this . getComponentByEl = el => appContext . getComponentByEl ( el ) ;
2018-12-22 20:57:09 +01:00
/ * *
* @ method
2023-01-05 23:38:41 +01:00
* @ param { object } $el - jquery object on which to set up the tooltip
* @ returns { Promise < void > }
2018-12-22 20:57:09 +01:00
* /
2019-01-01 15:39:13 +01:00
this . setupElementTooltip = noteTooltipService . setupElementTooltip ;
2020-02-26 16:37:17 +01:00
/ * *
* @ method
* @ param { string } noteId
* @ param { boolean } protect - true to protect note , false to unprotect
2023-01-05 23:38:41 +01:00
* @ returns { Promise < void > }
2020-02-26 16:37:17 +01:00
* /
this . protectNote = async ( noteId , protect ) => {
await protectedSessionService . protectNote ( noteId , protect , false ) ;
} ;
/ * *
* @ method
* @ param { string } noteId
* @ param { boolean } protect - true to protect subtree , false to unprotect
2023-01-05 23:38:41 +01:00
* @ returns { Promise < void > }
2020-02-26 16:37:17 +01:00
* /
this . protectSubTree = async ( noteId , protect ) => {
await protectedSessionService . protectNote ( noteId , protect , true ) ;
} ;
2019-04-14 12:24:48 +02:00
/ * *
* Returns date - note for today . If it doesn ' t exist , it is automatically created .
*
* @ method
2023-01-05 23:38:41 +01:00
* @ returns { Promise < FNote > }
2019-04-14 12:24:48 +02:00
* /
this . getTodayNote = dateNotesService . getTodayNote ;
2021-10-21 03:16:51 -07:00
/ * *
2022-01-10 17:09:20 +01:00
* Returns day note for a given date . If it doesn ' t exist , it is automatically created .
*
* @ method
* @ param { string } date - e . g . "2019-04-29"
2023-01-05 23:38:41 +01:00
* @ returns { Promise < FNote > }
2022-01-10 17:09:20 +01:00
* /
this . getDayNote = dateNotesService . getDayNote ;
/ * *
* Returns day note for the first date of the week of the given date . If it doesn ' t exist , it is automatically created .
2021-10-21 03:16:51 -07:00
*
* @ method
* @ param { string } date - e . g . "2019-04-29"
2023-01-05 23:38:41 +01:00
* @ returns { Promise < FNote > }
2021-10-21 03:16:51 -07:00
* /
this . getWeekNote = dateNotesService . getWeekNote ;
2019-04-14 12:24:48 +02:00
/ * *
* Returns month - note . If it doesn ' t exist , it is automatically created .
*
* @ method
* @ param { string } month - e . g . "2019-04"
2023-01-05 23:38:41 +01:00
* @ returns { Promise < FNote > }
2019-04-14 12:24:48 +02:00
* /
this . getMonthNote = dateNotesService . getMonthNote ;
/ * *
* Returns year - note . If it doesn ' t exist , it is automatically created .
*
* @ method
* @ param { string } year - e . g . "2019"
2023-01-05 23:38:41 +01:00
* @ returns { Promise < FNote > }
2019-04-14 12:24:48 +02:00
* /
this . getYearNote = dateNotesService . getYearNote ;
2019-10-21 21:22:53 +02:00
/ * *
2020-11-23 22:52:48 +01:00
* Hoist note in the current tab . See https : //github.com/zadam/trilium/wiki/Note-hoisting
2019-10-21 21:22:53 +02:00
*
* @ method
* @ param { string } noteId - set hoisted note . 'root' will effectively unhoist
2023-01-05 23:38:41 +01:00
* @ returns { Promise < void > }
2019-10-21 21:22:53 +02:00
* /
2020-11-23 22:52:48 +01:00
this . setHoistedNoteId = ( noteId ) => {
2021-05-22 12:35:41 +02:00
const activeNoteContext = appContext . tabManager . getActiveContext ( ) ;
2020-11-23 22:52:48 +01:00
2021-05-22 12:26:45 +02:00
if ( activeNoteContext ) {
activeNoteContext . setHoistedNoteId ( noteId ) ;
2020-11-23 22:52:48 +01:00
}
} ;
2019-11-05 21:26:54 +01:00
/ * *
* @ method
* @ param { string } keyboardShortcut - e . g . "ctrl+shift+a"
* @ param { function } handler
2022-12-01 10:03:04 +01:00
* @ param { string } [ namespace ] - specify namespace of the handler for the cases where call for bind may be repeated .
* If a handler with this ID exists , it ' s replaced by the new handler .
2023-01-05 23:38:41 +01:00
* @ returns { Promise < void > }
2019-11-05 21:26:54 +01:00
* /
2022-12-01 00:17:15 +01:00
this . bindGlobalShortcut = shortcutService . bindGlobalShortcut ;
2019-12-09 23:07:45 +01:00
/ * *
2019-12-10 23:04:18 +01:00
* Trilium runs in backend and frontend process , when something is changed on the backend from script ,
* frontend will get asynchronously synchronized .
*
* This method returns a promise which resolves once all the backend - > frontend synchronization is finished .
* Typical use case is when new note has been created , we should wait until it is synced into frontend and only then activate it .
*
2019-12-09 23:07:45 +01:00
* @ method
2023-01-05 23:38:41 +01:00
* @ returns { Promise < void > }
2019-12-09 23:07:45 +01:00
* /
2020-08-02 23:27:48 +02:00
this . waitUntilSynced = ws . waitForMaxKnownEntityChangeId ;
2020-06-14 10:49:37 +02:00
/ * *
* This will refresh all currently opened notes which have included note specified in the parameter
*
* @ param includedNoteId - noteId of the included note
2023-01-05 23:38:41 +01:00
* @ returns { Promise < void > }
2020-06-14 10:49:37 +02:00
* /
this . refreshIncludedNote = includedNoteId => appContext . triggerEvent ( 'refreshIncludedNote' , { noteId : includedNoteId } ) ;
2021-04-07 22:01:52 +02:00
/ * *
* Return randomly generated string of given length . This random string generation is NOT cryptographically secure .
*
* @ method
* @ param { number } length of the string
* @ returns { string } random string
* /
this . randomString = utils . randomString ;
2022-09-17 23:06:17 +02:00
this . logMessages = { } ;
this . logSpacedUpdates = { } ;
/ * *
* Log given message to the log pane in UI
*
* @ param message
2023-01-05 23:38:41 +01:00
* @ returns { void }
2022-09-17 23:06:17 +02:00
* /
this . log = message => {
const { noteId } = this . startNote ;
2022-12-21 15:19:05 +01:00
message = ` ${ utils . now ( ) } : ${ message } ` ;
2022-09-17 23:06:17 +02:00
console . log ( ` Script ${ noteId } : ${ message } ` ) ;
this . logMessages [ noteId ] = this . logMessages [ noteId ] || [ ] ;
this . logSpacedUpdates [ noteId ] = this . logSpacedUpdates [ noteId ] || new SpacedUpdate ( ( ) => {
const messages = this . logMessages [ noteId ] ;
this . logMessages [ noteId ] = [ ] ;
appContext . triggerEvent ( "apiLogMessages" , { noteId , messages } ) ;
} , 100 ) ;
this . logMessages [ noteId ] . push ( message ) ;
this . logSpacedUpdates [ noteId ] . scheduleUpdate ( ) ;
} ;
2018-08-23 12:55:45 +02:00
}
2020-06-14 10:49:37 +02:00
export default FrontendScriptApi ;