2018-03-25 13:41:29 -04:00
import treeService from './tree.js' ;
2018-04-08 22:38:52 -04:00
import treeUtils from './tree_utils.js' ;
2018-03-25 13:41:29 -04:00
import noteTypeService from './note_type.js' ;
import protectedSessionService from './protected_session.js' ;
2018-03-25 21:16:57 -04:00
import protectedSessionHolder from './protected_session_holder.js' ;
2018-03-25 11:09:17 -04:00
import utils from './utils.js' ;
import server from './server.js' ;
2018-03-25 21:16:57 -04:00
import messagingService from "./messaging.js" ;
2018-03-25 21:29:35 -04:00
import infoService from "./info.js" ;
2018-07-28 17:59:55 +02:00
import linkService from "./link.js" ;
2018-03-25 23:25:17 -04:00
import treeCache from "./tree_cache.js" ;
import NoteFull from "../entities/note_full.js" ;
2018-03-27 00:22:02 -04:00
import noteDetailCode from './note_detail_code.js' ;
import noteDetailText from './note_detail_text.js' ;
2018-03-27 22:11:06 -04:00
import noteDetailFile from './note_detail_file.js' ;
2018-03-27 21:36:01 -04:00
import noteDetailSearch from './note_detail_search.js' ;
import noteDetailRender from './note_detail_render.js' ;
2018-07-29 16:06:13 +02:00
import bundleService from "./bundle.js" ;
2018-08-06 22:29:03 +02:00
import noteAutocompleteService from "./note_autocomplete.js" ;
2018-03-25 11:09:17 -04:00
const $noteTitle = $ ( "#note-title" ) ;
2018-03-27 00:22:02 -04:00
const $noteDetailComponents = $ ( ".note-detail-component" ) ;
2018-03-25 11:09:17 -04:00
const $protectButton = $ ( "#protect-button" ) ;
const $unprotectButton = $ ( "#unprotect-button" ) ;
const $noteDetailWrapper = $ ( "#note-detail-wrapper" ) ;
const $noteIdDisplay = $ ( "#note-id-display" ) ;
2018-08-06 09:41:01 +02:00
const $attributeList = $ ( "#attribute-list" ) ;
const $attributeListInner = $ ( "#attribute-list-inner" ) ;
2018-04-08 22:38:52 -04:00
const $childrenOverview = $ ( "#children-overview" ) ;
2018-07-29 16:06:13 +02:00
const $scriptArea = $ ( "#note-detail-script-area" ) ;
2018-08-06 14:43:42 +02:00
const $promotedAttributesContainer = $ ( "#note-detail-promoted-attributes" ) ;
2018-03-25 11:09:17 -04:00
let currentNote = null ;
let noteChangeDisabled = false ;
let isNoteChanged = false ;
2018-08-28 20:55:21 +02:00
let attributePromise ;
2018-03-27 21:46:38 -04:00
const components = {
'code' : noteDetailCode ,
'text' : noteDetailText ,
2018-03-27 22:11:06 -04:00
'file' : noteDetailFile ,
2018-03-27 21:46:38 -04:00
'search' : noteDetailSearch ,
'render' : noteDetailRender
} ;
function getComponent ( type ) {
if ( components [ type ] ) {
return components [ type ] ;
}
else {
infoService . throwError ( "Unrecognized type: " + type ) ;
}
}
2018-03-25 11:09:17 -04:00
function getCurrentNote ( ) {
return currentNote ;
}
function getCurrentNoteId ( ) {
2018-03-25 23:25:17 -04:00
return currentNote ? currentNote . noteId : null ;
2018-03-25 11:09:17 -04:00
}
2018-03-27 00:22:02 -04:00
function getCurrentNoteType ( ) {
const currentNote = getCurrentNote ( ) ;
return currentNote ? currentNote . type : null ;
}
2018-03-25 11:09:17 -04:00
function noteChanged ( ) {
if ( noteChangeDisabled ) {
return ;
}
2018-03-24 00:54:50 -04:00
2018-03-25 11:09:17 -04:00
isNoteChanged = true ;
}
2017-11-04 17:54:27 -04:00
2018-03-25 11:09:17 -04:00
async function reload ( ) {
// no saving here
2017-11-04 17:54:27 -04:00
2018-04-08 22:38:52 -04:00
await loadNoteDetail ( getCurrentNoteId ( ) ) ;
2018-03-25 11:09:17 -04:00
}
2017-11-04 17:54:27 -04:00
2018-03-25 11:09:17 -04:00
async function switchToNote ( noteId ) {
if ( getCurrentNoteId ( ) !== noteId ) {
await saveNoteIfChanged ( ) ;
2017-11-04 17:54:27 -04:00
2018-04-08 22:38:52 -04:00
await loadNoteDetail ( noteId ) ;
2017-11-04 17:54:27 -04:00
}
2018-03-25 11:09:17 -04:00
}
2017-11-04 17:54:27 -04:00
2018-04-08 08:21:49 -04:00
async function saveNote ( ) {
2018-03-25 11:09:17 -04:00
const note = getCurrentNote ( ) ;
2017-11-04 17:54:27 -04:00
2018-03-27 21:36:01 -04:00
note . title = $noteTitle . val ( ) ;
2018-03-27 21:46:38 -04:00
note . content = getComponent ( note . type ) . getContent ( ) ;
2017-11-04 17:54:27 -04:00
2018-08-31 00:08:04 +02:00
// it's important to set the flag back to false immediatelly after retrieving title and content
// otherwise we might overwrite another change (especially async code)
isNoteChanged = false ;
2018-03-27 21:36:01 -04:00
treeService . setNoteTitle ( note . noteId , note . title ) ;
2017-11-04 17:54:27 -04:00
2018-04-08 08:21:49 -04:00
await server . put ( 'notes/' + note . noteId , note . dto ) ;
2017-11-14 22:50:56 -05:00
2017-11-04 17:54:27 -04:00
2018-04-08 08:21:49 -04:00
if ( note . isProtected ) {
protectedSessionHolder . touchProtectedSession ( ) ;
}
2018-03-25 21:29:35 -04:00
infoService . showMessage ( "Saved!" ) ;
2018-03-25 11:09:17 -04:00
}
2018-01-26 19:54:27 -05:00
2018-04-08 08:21:49 -04:00
async function saveNoteIfChanged ( ) {
if ( ! isNoteChanged ) {
return ;
}
await saveNote ( ) ;
}
2018-03-25 11:09:17 -04:00
function setNoteBackgroundIfProtected ( note ) {
2018-08-28 14:26:11 +02:00
$noteDetailWrapper . toggleClass ( "protected" , note . isProtected ) ;
$protectButton . toggleClass ( "active" , note . isProtected ) ;
$unprotectButton . toggleClass ( "active" , ! note . isProtected ) ;
2018-08-17 15:21:59 +02:00
$unprotectButton . prop ( "disabled" , ! protectedSessionHolder . isProtectedSessionAvailable ( ) ) ;
2018-03-25 11:09:17 -04:00
}
2017-11-04 17:54:27 -04:00
2018-03-25 11:09:17 -04:00
let isNewNoteCreated = false ;
2017-11-04 17:54:27 -04:00
2018-03-25 11:09:17 -04:00
function newNoteCreated ( ) {
isNewNoteCreated = true ;
}
2017-11-04 17:54:27 -04:00
2018-03-27 00:22:02 -04:00
async function handleProtectedSession ( ) {
2018-08-28 15:03:23 +02:00
const newSessionCreated = await protectedSessionService . ensureProtectedSession ( currentNote . isProtected , false ) ;
2018-03-27 00:22:02 -04:00
if ( currentNote . isProtected ) {
protectedSessionHolder . touchProtectedSession ( ) ;
}
// this might be important if we focused on protected note when not in protected note and we got a dialog
// to login, but we chose instead to come to another node - at that point the dialog is still visible and this will close it.
protectedSessionService . ensureDialogIsClosed ( ) ;
2018-08-28 15:03:23 +02:00
return newSessionCreated ;
2018-03-27 00:22:02 -04:00
}
2018-04-08 22:38:52 -04:00
async function loadNoteDetail ( noteId ) {
2018-03-25 11:09:17 -04:00
currentNote = await loadNote ( noteId ) ;
2018-08-28 20:55:21 +02:00
refreshAttributes ( ) ; // needs to happend after loading the note itself because it references current noteId
2018-02-12 23:53:00 -05:00
2018-03-25 11:09:17 -04:00
if ( isNewNoteCreated ) {
isNewNoteCreated = false ;
2018-02-24 14:42:52 -05:00
2018-03-25 11:09:17 -04:00
$noteTitle . focus ( ) . select ( ) ;
}
2018-03-11 10:49:22 -04:00
2018-03-25 11:09:17 -04:00
$noteIdDisplay . html ( noteId ) ;
2018-03-11 10:49:22 -04:00
2018-06-02 11:47:16 -04:00
setNoteBackgroundIfProtected ( currentNote ) ;
2018-03-25 11:09:17 -04:00
$noteDetailWrapper . show ( ) ;
2017-11-04 17:54:27 -04:00
2018-03-25 11:09:17 -04:00
noteChangeDisabled = true ;
2017-11-04 17:54:27 -04:00
2018-03-27 00:22:02 -04:00
try {
$noteTitle . val ( currentNote . title ) ;
2017-12-25 09:46:11 -05:00
2018-03-27 00:22:02 -04:00
noteTypeService . setNoteType ( currentNote . type ) ;
noteTypeService . setNoteMime ( currentNote . mime ) ;
2017-11-04 17:54:27 -04:00
2018-03-27 00:22:02 -04:00
$noteDetailComponents . hide ( ) ;
2017-11-14 22:50:56 -05:00
2018-08-28 15:03:23 +02:00
const newSessionCreated = await handleProtectedSession ( ) ;
if ( newSessionCreated ) {
// in such case we're reloading note anyway so no need to continue here.
return ;
}
2018-08-17 15:21:59 +02:00
2018-03-27 21:46:38 -04:00
await getComponent ( currentNote . type ) . show ( ) ;
2018-03-26 23:48:45 -04:00
}
2018-03-27 00:22:02 -04:00
finally {
noteChangeDisabled = false ;
2018-03-25 11:09:17 -04:00
}
2018-01-21 23:36:09 -05:00
2018-03-25 11:09:17 -04:00
treeService . setBranchBackgroundBasedOnProtectedStatus ( noteId ) ;
2018-01-23 23:41:22 -05:00
2018-03-25 11:09:17 -04:00
// after loading new note make sure editor is scrolled to the top
$noteDetailWrapper . scrollTop ( 0 ) ;
2018-01-23 23:41:22 -05:00
2018-08-28 14:26:11 +02:00
$scriptArea . empty ( ) ;
2018-07-29 20:51:28 +02:00
2018-07-29 18:39:10 +02:00
await bundleService . executeRelationBundles ( getCurrentNote ( ) , 'runOnNoteView' ) ;
2018-08-06 08:59:26 +02:00
2018-08-28 20:55:21 +02:00
await showAttributes ( ) ;
2018-08-07 12:48:11 +02:00
2018-08-28 20:55:21 +02:00
await showChildrenOverview ( ) ;
2018-04-08 22:38:52 -04:00
}
2018-08-28 20:55:21 +02:00
async function showChildrenOverview ( ) {
const attributes = await attributePromise ;
const hideChildrenOverview = attributes . some ( attr => attr . type === 'label' && attr . name === 'hideChildrenOverview' ) ;
2018-04-10 23:15:41 -04:00
if ( hideChildrenOverview ) {
$childrenOverview . hide ( ) ;
return ;
}
2018-04-08 22:38:52 -04:00
const note = getCurrentNote ( ) ;
$childrenOverview . empty ( ) ;
const notePath = treeService . getCurrentNotePath ( ) ;
for ( const childBranch of await note . getChildBranches ( ) ) {
const link = $ ( '<a>' , {
href : 'javascript:' ,
text : await treeUtils . getNoteTitle ( childBranch . noteId , childBranch . parentNoteId )
2018-08-15 10:14:14 +02:00
} ) . attr ( 'data-action' , 'note' ) . attr ( 'data-note-path' , notePath + '/' + childBranch . noteId ) ;
2018-04-08 22:38:52 -04:00
const childEl = $ ( '<div class="child-overview">' ) . html ( link ) ;
$childrenOverview . append ( childEl ) ;
}
2018-04-10 23:15:41 -04:00
$childrenOverview . show ( ) ;
2018-03-25 11:09:17 -04:00
}
2018-03-07 00:17:18 -05:00
2018-08-28 20:55:21 +02:00
async function refreshAttributes ( ) {
attributePromise = server . get ( 'notes/' + getCurrentNoteId ( ) + '/attributes' ) ;
await showAttributes ( ) ;
}
async function getAttributes ( ) {
return await attributePromise ;
}
async function showAttributes ( ) {
2018-08-06 14:43:42 +02:00
$promotedAttributesContainer . empty ( ) ;
2018-08-07 11:38:00 +02:00
$attributeList . hide ( ) ;
2018-08-06 08:59:26 +02:00
const noteId = getCurrentNoteId ( ) ;
2018-08-28 20:55:21 +02:00
const attributes = await attributePromise ;
2018-08-06 08:59:26 +02:00
2018-08-27 13:35:45 +02:00
const promoted = attributes . filter ( attr =>
( attr . type === 'label-definition' || attr . type === 'relation-definition' )
&& ! attr . name . startsWith ( "child:" )
&& attr . value . isPromoted ) ;
2018-08-06 08:59:26 +02:00
2018-08-14 13:50:04 +02:00
let idx = 1 ;
2018-08-06 08:59:26 +02:00
2018-08-06 17:24:35 +02:00
async function createRow ( definitionAttr , valueAttr ) {
const definition = definitionAttr . value ;
2018-08-13 09:07:21 +02:00
const inputId = "promoted-input-" + idx ;
2018-08-06 17:24:35 +02:00
const $tr = $ ( "<tr>" ) ;
const $labelCell = $ ( "<th>" ) . append ( valueAttr . name ) ;
const $input = $ ( "<input>" )
. prop ( "id" , inputId )
2018-08-14 13:50:04 +02:00
. prop ( "tabindex" , definitionAttr . position )
2018-08-07 11:38:00 +02:00
. prop ( "attribute-id" , valueAttr . isOwned ? valueAttr . attributeId : '' ) // if not owned, we'll force creation of a new attribute instead of updating the inherited one
2018-08-06 17:24:35 +02:00
. prop ( "attribute-type" , valueAttr . type )
. prop ( "attribute-name" , valueAttr . name )
. prop ( "value" , valueAttr . value )
. addClass ( "form-control" )
2018-08-29 22:28:58 +02:00
. addClass ( "promoted-attribute-input" )
. change ( promotedAttributeChanged ) ;
2018-08-06 17:24:35 +02:00
2018-08-13 09:07:21 +02:00
idx ++ ;
2018-08-06 22:29:03 +02:00
const $inputCell = $ ( "<td>" ) . append ( $ ( "<div>" ) . addClass ( "input-group" ) . append ( $input ) ) ;
2018-08-06 17:24:35 +02:00
const $actionCell = $ ( "<td>" ) ;
const $multiplicityCell = $ ( "<td>" ) ;
$tr
. append ( $labelCell )
. append ( $inputCell )
. append ( $actionCell )
. append ( $multiplicityCell ) ;
if ( valueAttr . type === 'label' ) {
if ( definition . labelType === 'text' ) {
$input . prop ( "type" , "text" ) ;
2018-08-06 22:52:49 +02:00
2018-08-13 15:58:37 +02:00
// no need to await for this, can be done asynchronously
server . get ( 'attributes/values/' + encodeURIComponent ( valueAttr . name ) ) . then ( attributeValues => {
if ( attributeValues . length === 0 ) {
return ;
}
$input . autocomplete ( {
// shouldn't be required and autocomplete should just accept array of strings, but that fails
// because we have overriden filter() function in autocomplete.js
source : attributeValues . map ( attribute => {
return {
attribute : attribute ,
value : attribute
}
} ) ,
minLength : 0
} ) ;
$input . focus ( ( ) => $input . autocomplete ( "search" , "" ) ) ;
2018-08-06 22:52:49 +02:00
} ) ;
2018-08-06 17:24:35 +02:00
}
else if ( definition . labelType === 'number' ) {
$input . prop ( "type" , "number" ) ;
}
else if ( definition . labelType === 'boolean' ) {
$input . prop ( "type" , "checkbox" ) ;
if ( valueAttr . value === "true" ) {
$input . prop ( "checked" , "checked" ) ;
}
}
else if ( definition . labelType === 'date' ) {
$input . prop ( "type" , "text" ) ;
$input . datepicker ( {
changeMonth : true ,
changeYear : true ,
2018-08-21 12:50:43 +02:00
yearRange : "c-200:c+10" ,
2018-08-06 17:24:35 +02:00
dateFormat : "yy-mm-dd"
} ) ;
const $todayButton = $ ( "<button>" ) . addClass ( "btn btn-small" ) . text ( "Today" ) . click ( ( ) => {
$input . val ( utils . formatDateISO ( new Date ( ) ) ) ;
$input . trigger ( "change" ) ;
} ) ;
$actionCell . append ( $todayButton ) ;
}
2018-08-18 15:00:52 +02:00
else if ( definition . labelType === 'url' ) {
$input . prop ( "placeholder" , "http://website..." ) ;
const $openButton = $ ( "<button>" ) . addClass ( "btn btn-small" ) . text ( "Open" ) . click ( ( ) => {
window . open ( $input . val ( ) , '_blank' ) ;
} ) ;
$actionCell . append ( $openButton ) ;
}
2018-08-06 17:24:35 +02:00
else {
messagingService . logError ( "Unknown labelType=" + definitionAttr . labelType ) ;
}
}
2018-08-06 22:29:03 +02:00
else if ( valueAttr . type === 'relation' ) {
if ( valueAttr . value ) {
$input . val ( ( await treeUtils . getNoteTitle ( valueAttr . value ) + " (" + valueAttr . value + ")" ) ) ;
}
2018-08-14 13:50:04 +02:00
// no need to wait for this
noteAutocompleteService . initNoteAutocomplete ( $input ) ;
2018-08-18 14:55:27 +02:00
// ideally we'd use link instead of button which would allow tooltip preview, but
// we can't guarantee updating the link in the a element
const $openButton = $ ( "<button>" ) . addClass ( "btn btn-small" ) . text ( "Open" ) . click ( ( ) => {
const notePath = linkService . getNotePathFromLabel ( $input . val ( ) ) ;
2018-08-23 12:55:45 +02:00
treeService . activateNote ( notePath ) ;
2018-08-18 14:55:27 +02:00
} ) ;
$actionCell . append ( $openButton ) ;
2018-08-06 22:29:03 +02:00
}
else {
messagingService . logError ( "Unknown attribute type=" + valueAttr . type ) ;
return ;
}
2018-08-06 17:24:35 +02:00
if ( definition . multiplicityType === "multivalue" ) {
2018-08-06 17:53:13 +02:00
const addButton = $ ( "<span>" )
. addClass ( "glyphicon glyphicon-plus pointer" )
. prop ( "title" , "Add new attribute" )
. click ( async ( ) => {
2018-08-06 17:24:35 +02:00
const $new = await createRow ( definitionAttr , {
attributeId : "" ,
type : valueAttr . type ,
name : definitionAttr . name ,
value : ""
} ) ;
$tr . after ( $new ) ;
2018-08-14 13:50:04 +02:00
$new . find ( 'input' ) . focus ( ) ;
2018-08-06 17:24:35 +02:00
} ) ;
2018-08-06 17:53:13 +02:00
const removeButton = $ ( "<span>" )
. addClass ( "glyphicon glyphicon-trash pointer" )
. prop ( "title" , "Remove this attribute" )
. click ( async ( ) => {
2018-08-06 17:24:35 +02:00
if ( valueAttr . attributeId ) {
await server . remove ( "notes/" + noteId + "/attributes/" + valueAttr . attributeId ) ;
}
$tr . remove ( ) ;
} ) ;
2018-08-06 17:53:13 +02:00
$multiplicityCell . append ( addButton ) . append ( " " ) . append ( removeButton ) ;
2018-08-06 17:24:35 +02:00
}
2018-08-13 15:58:37 +02:00
2018-08-06 17:24:35 +02:00
return $tr ;
}
2018-08-06 08:59:26 +02:00
if ( promoted . length > 0 ) {
2018-08-14 13:50:04 +02:00
const $tbody = $ ( "<tbody>" ) ;
2018-08-06 14:43:42 +02:00
for ( const definitionAttr of promoted ) {
2018-08-06 15:23:22 +02:00
const definitionType = definitionAttr . type ;
const valueType = definitionType . substr ( 0 , definitionType . length - 11 ) ;
2018-08-06 17:24:35 +02:00
let valueAttrs = attributes . filter ( el => el . name === definitionAttr . name && el . type === valueType ) ;
2018-08-06 14:43:42 +02:00
if ( valueAttrs . length === 0 ) {
valueAttrs . push ( {
attributeId : "" ,
2018-08-06 15:23:22 +02:00
type : valueType ,
2018-08-06 14:43:42 +02:00
name : definitionAttr . name ,
value : ""
} ) ;
}
2018-08-06 17:24:35 +02:00
if ( definitionAttr . value . multiplicityType === 'singlevalue' ) {
valueAttrs = valueAttrs . slice ( 0 , 1 ) ;
}
2018-08-06 14:43:42 +02:00
for ( const valueAttr of valueAttrs ) {
2018-08-06 17:24:35 +02:00
const $tr = await createRow ( definitionAttr , valueAttr ) ;
2018-08-06 15:58:59 +02:00
2018-08-14 13:50:04 +02:00
$tbody . append ( $tr ) ;
2018-08-06 08:59:26 +02:00
}
}
2018-08-14 13:50:04 +02:00
// we replace the whole content in one step so there can't be any race conditions
// (previously we saw promoted attributes doubling)
$promotedAttributesContainer . empty ( ) . append ( $tbody ) ;
2018-08-06 08:59:26 +02:00
}
2018-08-06 09:41:01 +02:00
else {
2018-08-28 14:26:11 +02:00
$attributeListInner . empty ( ) ;
2018-08-06 09:41:01 +02:00
2018-08-06 15:23:22 +02:00
if ( attributes . length > 0 ) {
2018-08-06 09:41:01 +02:00
for ( const attribute of attributes ) {
if ( attribute . type === 'label' ) {
$attributeListInner . append ( utils . formatLabel ( attribute ) + " " ) ;
}
else if ( attribute . type === 'relation' ) {
2018-09-01 15:49:35 +02:00
$attributeListInner . append ( '@' + attribute . name + "=" ) ;
2018-08-06 09:41:01 +02:00
$attributeListInner . append ( await linkService . createNoteLink ( attribute . value ) ) ;
$attributeListInner . append ( " " ) ;
}
else if ( attribute . type === 'label-definition' || attribute . type === 'relation-definition' ) {
$attributeListInner . append ( attribute . name + " definition " ) ;
}
else {
messagingService . logError ( "Unknown attr type: " + attribute . type ) ;
}
}
$attributeList . show ( ) ;
}
}
2018-07-28 17:59:55 +02:00
2018-08-07 12:48:11 +02:00
return attributes ;
2018-07-28 17:59:55 +02:00
}
2018-08-29 22:28:58 +02:00
async function promotedAttributeChanged ( event ) {
2018-08-06 14:43:42 +02:00
const $attr = $ ( event . target ) ;
2018-08-06 15:23:22 +02:00
let value ;
if ( $attr . prop ( "type" ) === "checkbox" ) {
value = $attr . is ( ':checked' ) ? "true" : "false" ;
}
2018-08-06 22:29:03 +02:00
else if ( $attr . prop ( "attribute-type" ) === "relation" ) {
if ( $attr . val ( ) ) {
value = treeUtils . getNoteIdFromNotePath ( linkService . getNotePathFromLabel ( $attr . val ( ) ) ) ;
}
}
2018-08-06 15:23:22 +02:00
else {
value = $attr . val ( ) ;
}
2018-08-06 17:24:35 +02:00
const result = await server . put ( "notes/" + getCurrentNoteId ( ) + "/attribute" , {
2018-08-06 14:43:42 +02:00
attributeId : $attr . prop ( "attribute-id" ) ,
type : $attr . prop ( "attribute-type" ) ,
name : $attr . prop ( "attribute-name" ) ,
2018-08-06 15:23:22 +02:00
value : value
2018-08-06 14:43:42 +02:00
} ) ;
2018-08-06 17:24:35 +02:00
$attr . prop ( "attribute-id" , result . attributeId ) ;
2018-08-06 14:43:42 +02:00
infoService . showMessage ( "Attribute has been saved." ) ;
2018-08-29 22:28:58 +02:00
}
async function loadNote ( noteId ) {
const row = await server . get ( 'notes/' + noteId ) ;
return new NoteFull ( treeCache , row ) ;
}
function focus ( ) {
const note = getCurrentNote ( ) ;
getComponent ( note . type ) . focus ( ) ;
}
messagingService . subscribeToSyncMessages ( syncData => {
if ( syncData . some ( sync => sync . entityName === 'notes' && sync . entityId === getCurrentNoteId ( ) ) ) {
infoService . showMessage ( 'Reloading note because of background changes' ) ;
reload ( ) ;
}
2018-08-06 14:43:42 +02:00
} ) ;
2018-03-25 11:09:17 -04:00
$ ( document ) . ready ( ( ) => {
$noteTitle . on ( 'input' , ( ) => {
noteChanged ( ) ;
2017-11-29 21:13:12 -05:00
2018-03-25 11:09:17 -04:00
const title = $noteTitle . val ( ) ;
2017-11-04 17:54:27 -04:00
2018-03-25 11:09:17 -04:00
treeService . setNoteTitle ( getCurrentNoteId ( ) , title ) ;
2017-11-04 17:54:27 -04:00
} ) ;
2018-03-27 00:22:02 -04:00
noteDetailText . focus ( ) ;
2018-03-25 11:09:17 -04:00
} ) ;
2018-03-26 22:29:14 -04:00
// this makes sure that when user e.g. reloads the page or navigates away from the page, the note's content is saved
// this sends the request asynchronously and doesn't wait for result
2018-03-27 22:27:46 -04:00
$ ( window ) . on ( 'beforeunload' , ( ) => { saveNoteIfChanged ( ) ; } ) ; // don't convert to short form, handler doesn't like returned promise
2018-03-26 22:29:14 -04:00
2018-03-25 11:09:17 -04:00
setInterval ( saveNoteIfChanged , 5000 ) ;
export default {
reload ,
switchToNote ,
setNoteBackgroundIfProtected ,
loadNote ,
getCurrentNote ,
getCurrentNoteType ,
getCurrentNoteId ,
newNoteCreated ,
focus ,
2018-08-28 20:55:21 +02:00
getAttributes ,
showAttributes ,
refreshAttributes ,
2018-04-08 08:21:49 -04:00
saveNote ,
2018-03-27 00:22:02 -04:00
saveNoteIfChanged ,
noteChanged
2018-03-25 11:09:17 -04:00
} ;