mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 11:39:01 +01:00 
			
		
		
		
	chore(client/ts): port widgets/attribute_editor
This commit is contained in:
		
							parent
							
								
									b01725101d
								
							
						
					
					
						commit
						a349223e54
					
				| @ -19,7 +19,8 @@ import { ResolveOptions } from "../widgets/dialogs/delete_notes.js"; | |||||||
| import { PromptDialogOptions } from "../widgets/dialogs/prompt.js"; | import { PromptDialogOptions } from "../widgets/dialogs/prompt.js"; | ||||||
| import { ConfirmWithMessageOptions, ConfirmWithTitleOptions } from "../widgets/dialogs/confirm.js"; | import { ConfirmWithMessageOptions, ConfirmWithTitleOptions } from "../widgets/dialogs/confirm.js"; | ||||||
| import { Node } from "../services/tree.js"; | import { Node } from "../services/tree.js"; | ||||||
| import FAttribute from "../entities/fattribute.js"; | import LoadResults from "../services/load_results.js"; | ||||||
|  | import { Attribute } from "../services/attribute_parser.js"; | ||||||
| 
 | 
 | ||||||
| interface Layout { | interface Layout { | ||||||
|     getRootWidget: (appContext: AppContext) => RootWidget; |     getRootWidget: (appContext: AppContext) => RootWidget; | ||||||
| @ -36,7 +37,7 @@ interface BeforeUploadListener extends Component { | |||||||
| /** | /** | ||||||
|  * Base interface for the data/arguments for a given command (see {@link CommandMappings}). |  * Base interface for the data/arguments for a given command (see {@link CommandMappings}). | ||||||
|  */ |  */ | ||||||
| interface CommandData { | export interface CommandData { | ||||||
|     ntxId?: string; |     ntxId?: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -144,8 +145,13 @@ export type CommandMappings = { | |||||||
|     copyImageReferenceToClipboard: CommandData; |     copyImageReferenceToClipboard: CommandData; | ||||||
|     copyImageToClipboard: CommandData; |     copyImageToClipboard: CommandData; | ||||||
|     updateAttributesList: { |     updateAttributesList: { | ||||||
|         attributes: FAttribute[]; |         attributes: Attribute[]; | ||||||
|     }; |     }; | ||||||
|  | 
 | ||||||
|  |     addNewLabel: CommandData; | ||||||
|  |     addNewRelation: CommandData; | ||||||
|  |     addNewLabelDefinition: CommandData; | ||||||
|  |     addNewRelationDefinition: CommandData; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type EventMappings = { | type EventMappings = { | ||||||
| @ -162,8 +168,19 @@ type EventMappings = { | |||||||
|         noteId: string; |         noteId: string; | ||||||
|         messages: string[]; |         messages: string[]; | ||||||
|     }; |     }; | ||||||
|  |     entitiesReloaded: { | ||||||
|  |         loadResults: LoadResults | ||||||
|  |     }; | ||||||
|  |     addNewLabel: CommandData; | ||||||
|  |     addNewRelation: CommandData; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export type EventListener<T extends EventNames> = { | ||||||
|  |     [key in T as `${key}Event`]: (data: EventData<T>) => void | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export type EventData<T extends EventNames> = EventMappings[T]; | ||||||
|  | 
 | ||||||
| type CommandAndEventMappings = (CommandMappings & EventMappings); | type CommandAndEventMappings = (CommandMappings & EventMappings); | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -7,13 +7,14 @@ interface Token { | |||||||
|     endIndex: number; |     endIndex: number; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| interface Attribute { | export interface Attribute { | ||||||
|     type: AttributeType; |     type: AttributeType; | ||||||
|     name: string; |     name: string; | ||||||
|     isInheritable: boolean; |     isInheritable: boolean; | ||||||
|     value?: string; |     value?: string; | ||||||
|     startIndex: number; |     startIndex?: number; | ||||||
|     endIndex: number; |     endIndex?: number; | ||||||
|  |     noteId?: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function lex(str: string) { | function lex(str: string) { | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| import server from './server.js'; | import server from './server.js'; | ||||||
| import froca from './froca.js'; | import froca from './froca.js'; | ||||||
| import FNote from '../entities/fnote.js'; | import FNote from '../entities/fnote.js'; | ||||||
|  | import { AttributeRow } from './load_results.js'; | ||||||
| 
 | 
 | ||||||
| async function addLabel(noteId: string, name: string, value: string = "") { | async function addLabel(noteId: string, name: string, value: string = "") { | ||||||
|     await server.put(`notes/${noteId}/attribute`, { |     await server.put(`notes/${noteId}/attribute`, { | ||||||
| @ -23,18 +24,18 @@ async function removeAttributeById(noteId: string, attributeId: string) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @returns {boolean} - returns true if this attribute has the potential to influence the note in the argument. |  * @returns - returns true if this attribute has the potential to influence the note in the argument. | ||||||
|  *         That can happen in multiple ways: |  *         That can happen in multiple ways: | ||||||
|  *         1. attribute is owned by the note |  *         1. attribute is owned by the note | ||||||
|  *         2. attribute is owned by the template of the note |  *         2. attribute is owned by the template of the note | ||||||
|  *         3. attribute is owned by some note's ancestor and is inheritable |  *         3. attribute is owned by some note's ancestor and is inheritable | ||||||
|  */ |  */ | ||||||
| function isAffecting(this: { isInheritable: boolean }, attrRow: { noteId: string }, affectedNote: FNote) { | function isAffecting(attrRow: AttributeRow, affectedNote: FNote) { | ||||||
|     if (!affectedNote || !attrRow) { |     if (!affectedNote || !attrRow) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const attrNote = froca.notes[attrRow.noteId]; |     const attrNote = attrRow.noteId && froca.notes[attrRow.noteId]; | ||||||
| 
 | 
 | ||||||
|     if (!attrNote) { |     if (!attrNote) { | ||||||
|         // the note (owner of the attribute) is not even loaded into the cache, so it should not affect anything else
 |         // the note (owner of the attribute) is not even loaded into the cache, so it should not affect anything else
 | ||||||
| @ -50,6 +51,7 @@ function isAffecting(this: { isInheritable: boolean }, attrRow: { noteId: string | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO: This doesn't seem right.
 |     // TODO: This doesn't seem right.
 | ||||||
|  |     //@ts-ignore
 | ||||||
|     if (this.isInheritable) { |     if (this.isInheritable) { | ||||||
|         for (const owningNote of owningNotes) { |         for (const owningNote of owningNotes) { | ||||||
|             if (owningNote.hasAncestor(attrNote.noteId, true)) { |             if (owningNote.hasAncestor(attrNote.noteId, true)) { | ||||||
|  | |||||||
| @ -5,9 +5,11 @@ interface BranchRow { | |||||||
|     componentId: string; |     componentId: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| interface AttributeRow { | export interface AttributeRow { | ||||||
|  |     noteId?: string; | ||||||
|     attributeId: string; |     attributeId: string; | ||||||
|     componentId: string; |     componentId: string; | ||||||
|  |     isInheritable?: boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| interface RevisionRow { | interface RevisionRow { | ||||||
| @ -110,11 +112,11 @@ export default class LoadResults { | |||||||
|         this.attributeRows.push({attributeId, componentId}); |         this.attributeRows.push({attributeId, componentId}); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     getAttributeRows(componentId = 'none') { |     getAttributeRows(componentId = 'none'): AttributeRow[] { | ||||||
|         return this.attributeRows |         return this.attributeRows | ||||||
|             .filter(row => row.componentId !== componentId) |             .filter(row => row.componentId !== componentId) | ||||||
|             .map(row => this.getEntityRow("attributes", row.attributeId)) |             .map(row => this.getEntityRow("attributes", row.attributeId)) | ||||||
|             .filter(attr => !!attr); |             .filter(attr => !!attr) as AttributeRow[]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     addRevision(revisionId: string, noteId?: string, componentId?: string | null) { |     addRevision(revisionId: string, noteId?: string, componentId?: string | null) { | ||||||
|  | |||||||
| @ -30,14 +30,14 @@ interface Options { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function autocompleteSourceForCKEditor(queryText: string) { | async function autocompleteSourceForCKEditor(queryText: string) { | ||||||
|     return await new Promise((res, rej) => { |     return await new Promise<MentionItem[]>((res, rej) => { | ||||||
|         autocompleteSource(queryText, rows => { |         autocompleteSource(queryText, rows => { | ||||||
|             res(rows.map(row => { |             res(rows.map(row => { | ||||||
|                 return { |                 return { | ||||||
|                     action: row.action, |                     action: row.action, | ||||||
|                     noteTitle: row.noteTitle, |                     noteTitle: row.noteTitle, | ||||||
|                     id: `@${row.notePathTitle}`, |                     id: `@${row.notePathTitle}`, | ||||||
|                     name: row.notePathTitle, |                     name: row.notePathTitle || "", | ||||||
|                     link: `#${row.notePath}`, |                     link: `#${row.notePath}`, | ||||||
|                     notePath: row.notePath, |                     notePath: row.notePath, | ||||||
|                     highlightedNotePathTitle: row.highlightedNotePathTitle |                     highlightedNotePathTitle: row.highlightedNotePathTitle | ||||||
|  | |||||||
							
								
								
									
										85
									
								
								src/public/app/types.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										85
									
								
								src/public/app/types.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -144,4 +144,89 @@ declare global { | |||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|     var MERMAID_ELK: MermaidLoader; |     var MERMAID_ELK: MermaidLoader; | ||||||
|  | 
 | ||||||
|  |     var CKEditor: { | ||||||
|  |         BalloonEditor: { | ||||||
|  |             create(el: HTMLElement, config: { | ||||||
|  |                 removePlugins?: string[]; | ||||||
|  |                 toolbar: { | ||||||
|  |                     items: any[]; | ||||||
|  |                 }, | ||||||
|  |                 placeholder: string; | ||||||
|  |                 mention: MentionConfig | ||||||
|  |             }) | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     type TextEditorElement = {}; | ||||||
|  |     interface Writer { | ||||||
|  |         setAttribute(name: string, value: string, el: TextEditorElement); | ||||||
|  |         createPositionAt(el: TextEditorElement, opt?: "end"); | ||||||
|  |         setSelection(pos: number); | ||||||
|  |     } | ||||||
|  |     interface TextNode { | ||||||
|  |         previousSibling?: TextNode; | ||||||
|  |         name: string; | ||||||
|  |         data: string; | ||||||
|  |         startOffset: number; | ||||||
|  |         _attrs: { | ||||||
|  |             get(key: string): { | ||||||
|  |                 length: number | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     interface TextPosition { | ||||||
|  |         textNode: TextNode; | ||||||
|  |         offset: number; | ||||||
|  |     } | ||||||
|  |     interface TextEditor { | ||||||
|  |         model: { | ||||||
|  |             document: { | ||||||
|  |                 on(event: string, cb: () => void); | ||||||
|  |                 getRoot(): TextEditorElement; | ||||||
|  |                 selection: { | ||||||
|  |                     getFirstPosition(): undefined | TextPosition; | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|  |             change(cb: (writer: Writer) => void) | ||||||
|  |         }, | ||||||
|  |         editing: { | ||||||
|  |             view: { | ||||||
|  |                 document: { | ||||||
|  |                     on(event: string, cb: (event: { | ||||||
|  |                         stop(); | ||||||
|  |                     }, data: { | ||||||
|  |                         preventDefault(); | ||||||
|  |                     }) => void, opts?: { | ||||||
|  |                         priority: "high" | ||||||
|  |                     }); | ||||||
|  |                     getRoot(): TextEditorElement | ||||||
|  |                 }, | ||||||
|  |                 change(cb: (writer: Writer) => void) | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         getData(): string; | ||||||
|  |         setData(data: string): void; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     interface MentionItem { | ||||||
|  |         action?: string; | ||||||
|  |         noteTitle?: string; | ||||||
|  |         id: string; | ||||||
|  |         name: string; | ||||||
|  |         link?: string; | ||||||
|  |         notePath?: string; | ||||||
|  |         highlightedNotePathTitle?: string; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     interface MentionConfig { | ||||||
|  |         feeds: { | ||||||
|  |             marker: string; | ||||||
|  |             feed: (queryText: string) => MentionItem[] | Promise<MentionItem[]>; | ||||||
|  |             itemRenderer?: (item: { | ||||||
|  |                 highlightedNotePathTitle: string | ||||||
|  |             }) => void; | ||||||
|  |             minimumCharacters: number; | ||||||
|  |         }[]; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -12,6 +12,7 @@ import shortcutService from "../../services/shortcuts.js"; | |||||||
| import appContext from "../../components/app_context.js"; | import appContext from "../../components/app_context.js"; | ||||||
| import FAttribute from "../../entities/fattribute.js"; | import FAttribute from "../../entities/fattribute.js"; | ||||||
| import FNote, { FNoteRow } from "../../entities/fnote.js"; | import FNote, { FNoteRow } from "../../entities/fnote.js"; | ||||||
|  | import { Attribute } from "../../services/attribute_parser.js"; | ||||||
| 
 | 
 | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="attr-detail"> | <div class="attr-detail"> | ||||||
| @ -269,12 +270,12 @@ const ATTR_HELP: Record<string, Record<string, string>> = { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| interface AttributeDetailOpts { | interface AttributeDetailOpts { | ||||||
|     allAttributes: FAttribute[]; |     allAttributes: Attribute[]; | ||||||
|     attribute: FAttribute; |     attribute: Attribute; | ||||||
|     isOwned: boolean; |     isOwned: boolean; | ||||||
|     x: number; |     x: number; | ||||||
|     y: number; |     y: number; | ||||||
|     focus: "name"; |     focus?: "name"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| interface SearchRelatedResponse { | interface SearchRelatedResponse { | ||||||
| @ -319,8 +320,8 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|     private $attrHelp!: JQuery<HTMLElement>; |     private $attrHelp!: JQuery<HTMLElement>; | ||||||
| 
 | 
 | ||||||
|     private relatedNotesSpacedUpdate!: SpacedUpdate; |     private relatedNotesSpacedUpdate!: SpacedUpdate; | ||||||
|     private attribute!: FAttribute; |     private attribute!: Attribute; | ||||||
|     private allAttributes!: FAttribute[]; |     private allAttributes!: Attribute[]; | ||||||
|     private attrType!: ReturnType<AttributeDetailWidget["getAttrType"]>; |     private attrType!: ReturnType<AttributeDetailWidget["getAttrType"]>; | ||||||
| 
 | 
 | ||||||
|     async refresh() { |     async refresh() { | ||||||
| @ -475,7 +476,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|                 : (this.attrType === 'relation-definition' ? attribute.name.substr(9) : attribute.name); |                 : (this.attrType === 'relation-definition' ? attribute.name.substr(9) : attribute.name); | ||||||
| 
 | 
 | ||||||
|         const definition = this.attrType?.endsWith('-definition') |         const definition = this.attrType?.endsWith('-definition') | ||||||
|             ? promotedAttributeDefinitionParser.parse(attribute.value) |             ? promotedAttributeDefinitionParser.parse(attribute.value || "") | ||||||
|             : {}; |             : {}; | ||||||
| 
 | 
 | ||||||
|         if (this.attrType) { |         if (this.attrType) { | ||||||
| @ -492,8 +493,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
| 
 | 
 | ||||||
|         if (isOwned) { |         if (isOwned) { | ||||||
|             this.$attrIsOwnedBy.hide(); |             this.$attrIsOwnedBy.hide(); | ||||||
|         } |         } else if (attribute.noteId) { | ||||||
|         else { |  | ||||||
|             this.$attrIsOwnedBy |             this.$attrIsOwnedBy | ||||||
|                 .show() |                 .show() | ||||||
|                 .empty() |                 .empty() | ||||||
| @ -543,7 +543,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
| 
 | 
 | ||||||
|         if (attribute.type === 'label') { |         if (attribute.type === 'label') { | ||||||
|             this.$inputValue |             this.$inputValue | ||||||
|                 .val(attribute.value) |                 .val(attribute.value || "") | ||||||
|                 .attr('readonly', disabledFn); |                 .attr('readonly', disabledFn); | ||||||
|         } |         } | ||||||
|         else if (attribute.type === 'relation') { |         else if (attribute.type === 'relation') { | ||||||
| @ -696,7 +696,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     getAttrType(attribute: FAttribute) { |     getAttrType(attribute: Attribute) { | ||||||
|         if (attribute.type === 'label') { |         if (attribute.type === 'label') { | ||||||
|             if (attribute.name.startsWith('label:')) { |             if (attribute.name.startsWith('label:')) { | ||||||
|                 return "label-definition"; |                 return "label-definition"; | ||||||
|  | |||||||
| @ -3,13 +3,17 @@ import NoteContextAwareWidget from "../note_context_aware_widget.js"; | |||||||
| import noteAutocompleteService from "../../services/note_autocomplete.js"; | import noteAutocompleteService from "../../services/note_autocomplete.js"; | ||||||
| import server from "../../services/server.js"; | import server from "../../services/server.js"; | ||||||
| import contextMenuService from "../../menus/context_menu.js"; | import contextMenuService from "../../menus/context_menu.js"; | ||||||
| import attributeParser from "../../services/attribute_parser.js"; | import attributeParser, { Attribute } from "../../services/attribute_parser.js"; | ||||||
| import libraryLoader from "../../services/library_loader.js"; | import libraryLoader from "../../services/library_loader.js"; | ||||||
| import froca from "../../services/froca.js"; | import froca from "../../services/froca.js"; | ||||||
| import attributeRenderer from "../../services/attribute_renderer.js"; | import attributeRenderer from "../../services/attribute_renderer.js"; | ||||||
| import noteCreateService from "../../services/note_create.js"; | import noteCreateService from "../../services/note_create.js"; | ||||||
| import attributeService from "../../services/attributes.js"; | import attributeService from "../../services/attributes.js"; | ||||||
| import linkService from "../../services/link.js"; | import linkService from "../../services/link.js"; | ||||||
|  | import AttributeDetailWidget from "./attribute_detail.js"; | ||||||
|  | import { CommandData, EventData, EventListener, FilteredCommandNames } from "../../components/app_context.js"; | ||||||
|  | import FAttribute, { AttributeType } from "../../entities/fattribute.js"; | ||||||
|  | import FNote from "../../entities/fnote.js"; | ||||||
| 
 | 
 | ||||||
| const HELP_TEXT = ` | const HELP_TEXT = ` | ||||||
| <p>${t("attribute_editor.help_text_body1")}</p> | <p>${t("attribute_editor.help_text_body1")}</p> | ||||||
| @ -79,7 +83,7 @@ const TPL = ` | |||||||
| </div> | </div> | ||||||
| `;
 | `;
 | ||||||
| 
 | 
 | ||||||
| const mentionSetup = { | const mentionSetup: MentionConfig = { | ||||||
|     feeds: [ |     feeds: [ | ||||||
|         { |         { | ||||||
|             marker: '@', |             marker: '@', | ||||||
| @ -96,7 +100,7 @@ const mentionSetup = { | |||||||
|         { |         { | ||||||
|             marker: '#', |             marker: '#', | ||||||
|             feed: async queryText => { |             feed: async queryText => { | ||||||
|                 const names = await server.get(`attribute-names/?type=label&query=${encodeURIComponent(queryText)}`); |                 const names = await server.get<string[]>(`attribute-names/?type=label&query=${encodeURIComponent(queryText)}`); | ||||||
| 
 | 
 | ||||||
|                 return names.map(name => { |                 return names.map(name => { | ||||||
|                     return { |                     return { | ||||||
| @ -110,7 +114,7 @@ const mentionSetup = { | |||||||
|         { |         { | ||||||
|             marker: '~', |             marker: '~', | ||||||
|             feed: async queryText => { |             feed: async queryText => { | ||||||
|                 const names = await server.get(`attribute-names/?type=relation&query=${encodeURIComponent(queryText)}`); |                 const names = await server.get<string[]>(`attribute-names/?type=relation&query=${encodeURIComponent(queryText)}`); | ||||||
| 
 | 
 | ||||||
|                 return names.map(name => { |                 return names.map(name => { | ||||||
|                     return { |                     return { | ||||||
| @ -179,8 +183,24 @@ const editorConfig = { | |||||||
|     mention: mentionSetup |     mention: mentionSetup | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export default class AttributeEditorWidget extends NoteContextAwareWidget { | type AttributeCommandNames = FilteredCommandNames<CommandData>; | ||||||
|     constructor(attributeDetailWidget) { | 
 | ||||||
|  | export default class AttributeEditorWidget extends NoteContextAwareWidget implements | ||||||
|  |     EventListener<"entitiesReloaded">, | ||||||
|  |     EventListener<"addNewLabel">, | ||||||
|  |     EventListener<"addNewRelation"> { | ||||||
|  | 
 | ||||||
|  |     private attributeDetailWidget: AttributeDetailWidget; | ||||||
|  |     private $editor!: JQuery<HTMLElement>; | ||||||
|  |     private $addNewAttributeButton!: JQuery<HTMLElement>; | ||||||
|  |     private $saveAttributesButton!: JQuery<HTMLElement>; | ||||||
|  |     private $errors!: JQuery<HTMLElement>; | ||||||
|  | 
 | ||||||
|  |     private textEditor!: TextEditor; | ||||||
|  |     private lastUpdatedNoteId!: string | undefined; | ||||||
|  |     private lastSavedContent!: string; | ||||||
|  | 
 | ||||||
|  |     constructor(attributeDetailWidget: AttributeDetailWidget) { | ||||||
|         super(); |         super(); | ||||||
| 
 | 
 | ||||||
|         this.attributeDetailWidget = attributeDetailWidget; |         this.attributeDetailWidget = attributeDetailWidget; | ||||||
| @ -212,8 +232,8 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { | |||||||
|         this.$errors = this.$widget.find('.attribute-errors'); |         this.$errors = this.$widget.find('.attribute-errors'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     addNewAttribute(e) { |     addNewAttribute(e: JQuery.ClickEvent) { | ||||||
|         contextMenuService.show({ |         contextMenuService.show<AttributeCommandNames>({ | ||||||
|             x: e.pageX, |             x: e.pageX, | ||||||
|             y: e.pageY, |             y: e.pageY, | ||||||
|             orientation: 'left', |             orientation: 'left', | ||||||
| @ -229,7 +249,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // triggered from keyboard shortcut
 |     // triggered from keyboard shortcut
 | ||||||
|     async addNewLabelEvent({ntxId}) { |     async addNewLabelEvent({ntxId}: EventData<"addNewLabel">) { | ||||||
|         if (this.isNoteContext(ntxId)) { |         if (this.isNoteContext(ntxId)) { | ||||||
|             await this.refresh(); |             await this.refresh(); | ||||||
| 
 | 
 | ||||||
| @ -238,7 +258,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // triggered from keyboard shortcut
 |     // triggered from keyboard shortcut
 | ||||||
|     async addNewRelationEvent({ntxId}) { |     async addNewRelationEvent({ntxId}: EventData<"addNewRelation">) { | ||||||
|         if (this.isNoteContext(ntxId)) { |         if (this.isNoteContext(ntxId)) { | ||||||
|             await this.refresh(); |             await this.refresh(); | ||||||
| 
 | 
 | ||||||
| @ -246,14 +266,17 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async handleAddNewAttributeCommand(command) { |     async handleAddNewAttributeCommand(command: AttributeCommandNames | undefined) { | ||||||
|         const attrs = this.parseAttributes(); |         // TODO: Not sure what the relation between FAttribute[] and Attribute[] is.
 | ||||||
|  |         const attrs = this.parseAttributes() as FAttribute[]; | ||||||
| 
 | 
 | ||||||
|         if (!attrs) { |         if (!attrs) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let type, name, value; |         let type: AttributeType; | ||||||
|  |         let name; | ||||||
|  |         let value; | ||||||
| 
 | 
 | ||||||
|         if (command === 'addNewLabel') { |         if (command === 'addNewLabel') { | ||||||
|             type = 'label'; |             type = 'label'; | ||||||
| @ -275,6 +298,8 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // TODO: Incomplete type
 | ||||||
|  |         //@ts-ignore
 | ||||||
|         attrs.push({ |         attrs.push({ | ||||||
|             type, |             type, | ||||||
|             name, |             name, | ||||||
| @ -326,8 +351,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { | |||||||
|     parseAttributes() { |     parseAttributes() { | ||||||
|         try { |         try { | ||||||
|             return attributeParser.lexAndParse(this.getPreprocessedData()); |             return attributeParser.lexAndParse(this.getPreprocessedData()); | ||||||
|         } |         } catch (e: any) { | ||||||
|         catch (e) { |  | ||||||
|             this.$errors.text(e.message).slideDown(); |             this.$errors.text(e.message).slideDown(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -376,7 +400,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async handleEditorClick(e) { |     async handleEditorClick(e: JQuery.ClickEvent) { | ||||||
|         const pos = this.textEditor.model.document.selection.getFirstPosition(); |         const pos = this.textEditor.model.document.selection.getFirstPosition(); | ||||||
| 
 | 
 | ||||||
|         if (pos && pos.textNode && pos.textNode.data) { |         if (pos && pos.textNode && pos.textNode.data) { | ||||||
| @ -395,7 +419,8 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { | |||||||
|             let matchedAttr = null; |             let matchedAttr = null; | ||||||
| 
 | 
 | ||||||
|             for (const attr of parsedAttrs) { |             for (const attr of parsedAttrs) { | ||||||
|                 if (clickIndex > attr.startIndex && clickIndex <= attr.endIndex) { |                 if (attr.startIndex && clickIndex > attr.startIndex && | ||||||
|  |                     attr.endIndex && clickIndex <= attr.endIndex) { | ||||||
|                     matchedAttr = attr; |                     matchedAttr = attr; | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
| @ -437,7 +462,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { | |||||||
|         this.$editor.tooltip('show'); |         this.$editor.tooltip('show'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     getClickIndex(pos) { |     getClickIndex(pos: TextPosition) { | ||||||
|         let clickIndex = pos.offset - pos.textNode.startOffset; |         let clickIndex = pos.offset - pos.textNode.startOffset; | ||||||
| 
 | 
 | ||||||
|         let curNode = pos.textNode; |         let curNode = pos.textNode; | ||||||
| @ -455,20 +480,19 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { | |||||||
|         return clickIndex; |         return clickIndex; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async loadReferenceLinkTitle($el, href) { |     async loadReferenceLinkTitle($el: JQuery<HTMLElement>, href: string) { | ||||||
|         const {noteId} = linkService.parseNavigationStateFromUrl(href); |         const {noteId} = linkService.parseNavigationStateFromUrl(href); | ||||||
|         const note = await froca.getNote(noteId, true); |         const note = noteId ? await froca.getNote(noteId, true) : null; | ||||||
| 
 |  | ||||||
|         const title = note ? note.title : '[missing]'; |         const title = note ? note.title : '[missing]'; | ||||||
| 
 | 
 | ||||||
|         $el.text(title); |         $el.text(title); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async refreshWithNote(note) { |     async refreshWithNote(note: FNote) { | ||||||
|         await this.renderOwnedAttributes(note.getOwnedAttributes(), true); |         await this.renderOwnedAttributes(note.getOwnedAttributes(), true); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async renderOwnedAttributes(ownedAttributes, saved) { |     async renderOwnedAttributes(ownedAttributes: FAttribute[], saved: boolean) { | ||||||
|         // attrs are not resorted if position changes after the initial load
 |         // attrs are not resorted if position changes after the initial load
 | ||||||
|         ownedAttributes.sort((a, b) => a.position - b.position); |         ownedAttributes.sort((a, b) => a.position - b.position); | ||||||
| 
 | 
 | ||||||
| @ -487,16 +511,19 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async createNoteForReferenceLink(title) { |     async createNoteForReferenceLink(title: string) { | ||||||
|         const {note} = await noteCreateService.createNoteWithTypePrompt(this.notePath, { |         let result; | ||||||
|  |         if (this.notePath) { | ||||||
|  |             result = await noteCreateService.createNoteWithTypePrompt(this.notePath, { | ||||||
|                 activate: false, |                 activate: false, | ||||||
|                 title: title |                 title: title | ||||||
|             }); |             }); | ||||||
| 
 |  | ||||||
|         return note.getBestNotePathString(); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|     async updateAttributeList(attributes) { |         return result?.note?.getBestNotePathString(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async updateAttributeList(attributes: FAttribute[]) { | ||||||
|         await this.renderOwnedAttributes(attributes, false); |         await this.renderOwnedAttributes(attributes, false); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -510,9 +537,10 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget { | |||||||
|         } ); |         } ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     entitiesReloadedEvent({loadResults}) { |     entitiesReloadedEvent({loadResults}: EventData<"entitiesReloaded">) { | ||||||
|         if (loadResults.getAttributeRows(this.componentId).find(attr => attributeService.isAffecting(attr, this.note))) { |         if (loadResults.getAttributeRows(this.componentId).find(attr => attributeService.isAffecting(attr, this.note))) { | ||||||
|             this.refresh(); |             this.refresh(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran