| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  | import TabAwareWidget from "./tab_aware_widget.js"; | 
					
						
							|  |  |  | import noteAutocompleteService from "../services/note_autocomplete.js"; | 
					
						
							|  |  |  | import server from "../services/server.js"; | 
					
						
							|  |  |  | import contextMenuService from "../services/context_menu.js"; | 
					
						
							|  |  |  | import attributesParser from "../services/attribute_parser.js"; | 
					
						
							|  |  |  | import libraryLoader from "../services/library_loader.js"; | 
					
						
							|  |  |  | import treeCache from "../services/tree_cache.js"; | 
					
						
							|  |  |  | import attributeRenderer from "../services/attribute_renderer.js"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const TPL = `
 | 
					
						
							|  |  |  | <div style="position: relative"> | 
					
						
							|  |  |  |     <style> | 
					
						
							|  |  |  |     .attribute-list-editor { | 
					
						
							|  |  |  |         border: 0 !important; | 
					
						
							|  |  |  |         outline: 0 !important; | 
					
						
							|  |  |  |         box-shadow: none !important; | 
					
						
							|  |  |  |         padding: 0 0 0 5px !important; | 
					
						
							|  |  |  |         margin: 0 !important; | 
					
						
							|  |  |  |         color: var(--muted-text-color); | 
					
						
							| 
									
										
										
										
											2020-07-23 00:19:50 +02:00
										 |  |  |         max-height: 100px; | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |         overflow: auto; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     .save-attributes-button { | 
					
						
							|  |  |  |         color: var(--muted-text-color); | 
					
						
							|  |  |  |         position: absolute;  | 
					
						
							|  |  |  |         bottom: 3px; | 
					
						
							|  |  |  |         right: 25px; | 
					
						
							|  |  |  |         cursor: pointer; | 
					
						
							|  |  |  |         border: 1px solid transparent; | 
					
						
							|  |  |  |         font-size: 130%; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     .add-new-attribute-button { | 
					
						
							|  |  |  |         color: var(--muted-text-color); | 
					
						
							|  |  |  |         position: absolute;  | 
					
						
							|  |  |  |         bottom: 3px; | 
					
						
							|  |  |  |         right: 0;  | 
					
						
							|  |  |  |         cursor: pointer; | 
					
						
							|  |  |  |         border: 1px solid transparent; | 
					
						
							|  |  |  |         font-size: 130%; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     .add-new-attribute-button:hover, .save-attributes-button:hover { | 
					
						
							|  |  |  |         border: 1px solid var(--main-border-color); | 
					
						
							|  |  |  |         border-radius: 2px; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |      | 
					
						
							|  |  |  |     .attribute-errors { | 
					
						
							|  |  |  |         color: red; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |     </style> | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     <div class="attribute-list-editor" tabindex="200"></div> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-18 00:20:24 +02:00
										 |  |  |     <div class="bx bx-save save-attributes-button" title="Save attributes <enter>"></div> | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |     <div class="bx bx-plus add-new-attribute-button" title="Add a new attribute"></div> | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |      | 
					
						
							|  |  |  |     <div class="attribute-errors" style="display: none;"></div> | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  | </div> | 
					
						
							|  |  |  | `;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const mentionSetup = { | 
					
						
							|  |  |  |     feeds: [ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             marker: '@', | 
					
						
							|  |  |  |             feed: queryText => { | 
					
						
							|  |  |  |                 return new Promise((res, rej) => { | 
					
						
							|  |  |  |                     noteAutocompleteService.autocompleteSource(queryText, rows => { | 
					
						
							|  |  |  |                         res(rows.map(row => { | 
					
						
							|  |  |  |                             return { | 
					
						
							|  |  |  |                                 id: '@' + row.notePathTitle, | 
					
						
							|  |  |  |                                 name: row.notePathTitle, | 
					
						
							|  |  |  |                                 link: '#' + row.notePath, | 
					
						
							|  |  |  |                                 notePath: row.notePath, | 
					
						
							|  |  |  |                                 highlightedNotePathTitle: row.highlightedNotePathTitle | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                         })); | 
					
						
							|  |  |  |                     }); | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             itemRenderer: item => { | 
					
						
							| 
									
										
										
										
											2020-08-12 23:39:05 +02:00
										 |  |  |                 const itemElement = document.createElement('button'); | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 itemElement.innerHTML = `${item.highlightedNotePathTitle} `; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 return itemElement; | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             minimumCharacters: 0 | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             marker: '#', | 
					
						
							|  |  |  |             feed: async queryText => { | 
					
						
							|  |  |  |                 const names = await server.get(`attributes/names/?type=label&query=${encodeURIComponent(queryText)}`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 return names.map(name => { | 
					
						
							|  |  |  |                     return { | 
					
						
							|  |  |  |                         id: '#' + name, | 
					
						
							|  |  |  |                         name: name | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             minimumCharacters: 0, | 
					
						
							|  |  |  |             attributeMention: true | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             marker: '~', | 
					
						
							|  |  |  |             feed: async queryText => { | 
					
						
							|  |  |  |                 const names = await server.get(`attributes/names/?type=relation&query=${encodeURIComponent(queryText)}`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 return names.map(name => { | 
					
						
							|  |  |  |                     return { | 
					
						
							|  |  |  |                         id: '~' + name, | 
					
						
							|  |  |  |                         name: name | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             minimumCharacters: 0, | 
					
						
							|  |  |  |             attributeMention: true | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const editorConfig = { | 
					
						
							|  |  |  |     removePlugins: [ | 
					
						
							|  |  |  |         'Enter', | 
					
						
							|  |  |  |         'ShiftEnter', | 
					
						
							|  |  |  |         'Heading', | 
					
						
							|  |  |  |         'Link', | 
					
						
							|  |  |  |         'Autoformat', | 
					
						
							|  |  |  |         'Bold', | 
					
						
							|  |  |  |         'Italic', | 
					
						
							|  |  |  |         'Underline', | 
					
						
							|  |  |  |         'Strikethrough', | 
					
						
							|  |  |  |         'Code', | 
					
						
							|  |  |  |         'Superscript', | 
					
						
							|  |  |  |         'Subscript', | 
					
						
							|  |  |  |         'BlockQuote', | 
					
						
							|  |  |  |         'Image', | 
					
						
							|  |  |  |         'ImageCaption', | 
					
						
							|  |  |  |         'ImageStyle', | 
					
						
							|  |  |  |         'ImageToolbar', | 
					
						
							|  |  |  |         'ImageUpload', | 
					
						
							|  |  |  |         'ImageResize', | 
					
						
							|  |  |  |         'List', | 
					
						
							|  |  |  |         'TodoList', | 
					
						
							|  |  |  |         'PasteFromOffice', | 
					
						
							|  |  |  |         'Table', | 
					
						
							|  |  |  |         'TableToolbar', | 
					
						
							|  |  |  |         'TableProperties', | 
					
						
							|  |  |  |         'TableCellProperties', | 
					
						
							|  |  |  |         'Indent', | 
					
						
							|  |  |  |         'IndentBlock', | 
					
						
							|  |  |  |         'BlockToolbar', | 
					
						
							|  |  |  |         'ParagraphButtonUI', | 
					
						
							|  |  |  |         'HeadingButtonsUI', | 
					
						
							|  |  |  |         'UploadimagePlugin', | 
					
						
							|  |  |  |         'InternalLinkPlugin', | 
					
						
							|  |  |  |         'MarkdownImportPlugin', | 
					
						
							|  |  |  |         'CuttonotePlugin', | 
					
						
							|  |  |  |         'TextTransformation', | 
					
						
							|  |  |  |         'Font', | 
					
						
							|  |  |  |         'FontColor', | 
					
						
							|  |  |  |         'FontBackgroundColor', | 
					
						
							|  |  |  |         'CodeBlock', | 
					
						
							|  |  |  |         'SelectAll', | 
					
						
							|  |  |  |         'IncludeNote', | 
					
						
							|  |  |  |         'CutToNote' | 
					
						
							|  |  |  |     ], | 
					
						
							|  |  |  |     toolbar: { | 
					
						
							|  |  |  |         items: [] | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2020-07-23 22:31:06 +02:00
										 |  |  |     placeholder: "Type the labels and relations here, e.g. #year=2020", | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |     mention: mentionSetup | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default class AttributeEditorWidget extends TabAwareWidget { | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |     constructor(attributeDetailWidget) { | 
					
						
							|  |  |  |         super(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.attributeDetailWidget = attributeDetailWidget; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |     doRender() { | 
					
						
							|  |  |  |         this.$widget = $(TPL); | 
					
						
							|  |  |  |         this.$editor = this.$widget.find('.attribute-list-editor'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.initialized = this.initEditor(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.$editor.on('keydown', async e => { | 
					
						
							|  |  |  |             const keycode = (e.keyCode ? e.keyCode : e.which); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (keycode === 13) { | 
					
						
							|  |  |  |                 this.triggerCommand('focusOnDetail', {tabId: this.tabContext.tabId}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 await this.save(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             this.attributeDetailWidget.hide(); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-18 00:20:24 +02:00
										 |  |  |         this.$editor.on('blur', () => this.save()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |         this.$addNewAttributeButton = this.$widget.find('.add-new-attribute-button'); | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |         this.$addNewAttributeButton.on('click', e => this.addNewAttribute(e)); | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |         this.$saveAttributesButton = this.$widget.find('.save-attributes-button'); | 
					
						
							|  |  |  |         this.$saveAttributesButton.on('click', () => this.save()); | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |         this.$errors = this.$widget.find('.attribute-errors'); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |     addNewAttribute(e) { | 
					
						
							|  |  |  |         contextMenuService.show({ | 
					
						
							|  |  |  |             x: e.pageX, | 
					
						
							|  |  |  |             y: e.pageY, | 
					
						
							|  |  |  |             orientation: 'left', | 
					
						
							|  |  |  |             items: [ | 
					
						
							|  |  |  |                 {title: "Add new label", command: "addNewLabel", uiIcon: "hash"}, | 
					
						
							|  |  |  |                 {title: "Add new relation", command: "addNewRelation", uiIcon: "transfer"}, | 
					
						
							|  |  |  |                 {title: "----"}, | 
					
						
							|  |  |  |                 {title: "Add new label definition", command: "addNewLabelDefinition", uiIcon: "empty"}, | 
					
						
							|  |  |  |                 {title: "Add new relation definition", command: "addNewRelationDefinition", uiIcon: "empty"}, | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |             selectMenuItemHandler: ({command}) => this.handleAddNewAttributeCommand(command) | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |     async handleAddNewAttributeCommand(command) { | 
					
						
							|  |  |  |         const attrs = this.parseAttributes(); | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |         if (!attrs) { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-18 23:45:28 +02:00
										 |  |  |         let type, name, value; | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (command === 'addNewLabel') { | 
					
						
							|  |  |  |             type = 'label'; | 
					
						
							| 
									
										
										
										
											2020-07-18 23:45:28 +02:00
										 |  |  |             name = 'myLabel'; | 
					
						
							|  |  |  |             value = ''; | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |         } else if (command === 'addNewRelation') { | 
					
						
							|  |  |  |             type = 'relation'; | 
					
						
							| 
									
										
										
										
											2020-07-18 23:45:28 +02:00
										 |  |  |             name = 'myRelation'; | 
					
						
							|  |  |  |             value = ''; | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |         } else if (command === 'addNewLabelDefinition') { | 
					
						
							|  |  |  |             type = 'label'; | 
					
						
							| 
									
										
										
										
											2020-07-18 23:45:28 +02:00
										 |  |  |             name = 'label:myLabel'; | 
					
						
							|  |  |  |             value = 'promoted,single,text'; | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |         } else if (command === 'addNewRelationDefinition') { | 
					
						
							|  |  |  |             type = 'label'; | 
					
						
							| 
									
										
										
										
											2020-07-18 23:45:28 +02:00
										 |  |  |             name = 'relation:myRelation'; | 
					
						
							|  |  |  |             value = 'promoted,single'; | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |         attrs.push({ | 
					
						
							|  |  |  |             type, | 
					
						
							|  |  |  |             name, | 
					
						
							| 
									
										
										
										
											2020-07-18 23:45:28 +02:00
										 |  |  |             value, | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |             isInheritable: false | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-18 00:20:24 +02:00
										 |  |  |         await this.renderOwnedAttributes(attrs, false); | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.$editor.scrollTop(this.$editor[0].scrollHeight); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const rect = this.$editor[0].getBoundingClientRect(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         setTimeout(() => { | 
					
						
							|  |  |  |             // showing a little bit later because there's a conflict with outside click closing the attr detail
 | 
					
						
							|  |  |  |             this.attributeDetailWidget.showAttributeDetail({ | 
					
						
							|  |  |  |                 allAttributes: attrs, | 
					
						
							|  |  |  |                 attribute: attrs[attrs.length - 1], | 
					
						
							|  |  |  |                 isOwned: true, | 
					
						
							|  |  |  |                 x: (rect.left + rect.right) / 2, | 
					
						
							|  |  |  |                 y: rect.bottom | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         }, 100); | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async save() { | 
					
						
							|  |  |  |         const attributes = this.parseAttributes(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (attributes) { | 
					
						
							|  |  |  |             await server.put(`notes/${this.noteId}/attributes`, attributes, this.componentId); | 
					
						
							| 
									
										
										
										
											2020-07-23 00:19:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             this.$saveAttributesButton.fadeOut(); | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parseAttributes() { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             const attrs = attributesParser.lexAndParse(this.textEditor.getData()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return attrs; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         catch (e) { | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |             this.$errors.show().text(e.message); | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async initEditor() { | 
					
						
							|  |  |  |         await libraryLoader.requireLibrary(libraryLoader.CKEDITOR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.$widget.show(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.$editor.on("click", e => this.handleEditorClick(e)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.textEditor = await BalloonEditor.create(this.$editor[0], editorConfig); | 
					
						
							|  |  |  |         this.textEditor.model.document.on('change:data', () => this.dataChanged()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // disable spellcheck for attribute editor
 | 
					
						
							|  |  |  |         this.textEditor.editing.view.change(writer => writer.setAttribute('spellcheck', 'false', this.textEditor.editing.view.document.getRoot())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         //await import(/* webpackIgnore: true */'../../libraries/ckeditor/inspector.js');
 | 
					
						
							|  |  |  |         //CKEditorInspector.attach(this.textEditor);
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dataChanged() { | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |         if (this.lastSavedContent === this.textEditor.getData()) { | 
					
						
							|  |  |  |             this.$saveAttributesButton.fadeOut(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             this.$saveAttributesButton.fadeIn(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (this.$errors.is(":visible")) { | 
					
						
							|  |  |  |             this.$errors.slideUp(); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async handleEditorClick(e) { | 
					
						
							|  |  |  |         const pos = this.textEditor.model.document.selection.getFirstPosition(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (pos && pos.textNode && pos.textNode.data) { | 
					
						
							|  |  |  |             const clickIndex = this.getClickIndex(pos); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |             let parsedAttrs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             try { | 
					
						
							|  |  |  |                 parsedAttrs = attributesParser.lexAndParse(this.textEditor.getData(), true); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             catch (e) { | 
					
						
							|  |  |  |                 // the input is incorrect because user messed up with it and now needs to fix it manually
 | 
					
						
							|  |  |  |                 return null; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             let matchedAttr = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (const attr of parsedAttrs) { | 
					
						
							| 
									
										
										
										
											2020-07-18 23:45:28 +02:00
										 |  |  |                 if (clickIndex > attr.startIndex && clickIndex <= attr.endIndex) { | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |                     matchedAttr = attr; | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             this.attributeDetailWidget.showAttributeDetail({ | 
					
						
							|  |  |  |                 allAttributes: parsedAttrs, | 
					
						
							|  |  |  |                 attribute: matchedAttr, | 
					
						
							|  |  |  |                 isOwned: true, | 
					
						
							|  |  |  |                 x: e.pageX, | 
					
						
							|  |  |  |                 y: e.pageY | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     getClickIndex(pos) { | 
					
						
							|  |  |  |         let clickIndex = pos.offset - pos.textNode.startOffset; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let curNode = pos.textNode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         while (curNode.previousSibling) { | 
					
						
							|  |  |  |             curNode = curNode.previousSibling; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (curNode.name === 'reference') { | 
					
						
							|  |  |  |                 clickIndex += curNode._attrs.get('notePath').length + 1; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 clickIndex += curNode.data.length; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return clickIndex; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async loadReferenceLinkTitle(noteId, $el) { | 
					
						
							|  |  |  |         const note = await treeCache.getNote(noteId, true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let title; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!note) { | 
					
						
							|  |  |  |             title = '[missing]'; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (!note.isDeleted) { | 
					
						
							|  |  |  |             title = note.title; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             title = note.isErased ? '[erased]' : `${note.title} (deleted)`; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $el.text(title); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async refreshWithNote(note) { | 
					
						
							| 
									
										
										
										
											2020-07-18 00:20:24 +02:00
										 |  |  |         await this.renderOwnedAttributes(note.getOwnedAttributes(), true); | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-18 00:20:24 +02:00
										 |  |  |     async renderOwnedAttributes(ownedAttributes, saved) { | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |         const $attributesContainer = $("<div>"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const attribute of ownedAttributes) { | 
					
						
							| 
									
										
										
										
											2020-08-13 23:23:57 +02:00
										 |  |  |             if (!attribute.isDeleted) { | 
					
						
							|  |  |  |                 attributeRenderer.renderAttribute(attribute, $attributesContainer, true); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.textEditor.setData($attributesContainer.html()); | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-18 00:20:24 +02:00
										 |  |  |         if (saved) { | 
					
						
							|  |  |  |             this.lastSavedContent = this.textEditor.getData(); | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-18 00:20:24 +02:00
										 |  |  |             this.$saveAttributesButton.fadeOut(0); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async focusOnAttributesEvent({tabId}) { | 
					
						
							|  |  |  |         if (this.tabContext.tabId === tabId) { | 
					
						
							|  |  |  |             this.$editor.trigger('focus'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:55:59 +02:00
										 |  |  |     updateAttributeList(attributes) { | 
					
						
							| 
									
										
										
										
											2020-07-18 00:20:24 +02:00
										 |  |  |         this.renderOwnedAttributes(attributes, false); | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-12 00:02:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     entitiesReloadedEvent({loadResults}) { | 
					
						
							|  |  |  |         if (loadResults.getAttributes(this.componentId).find(attr => attr.isAffecting(this.note))) { | 
					
						
							|  |  |  |             this.refresh(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-17 00:08:28 +02:00
										 |  |  | } |