mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	chore(client/ts): port widgets/attribute_widgets/attribute_detail
This commit is contained in:
		| @@ -12,6 +12,7 @@ import utils from '../services/utils.js'; | |||||||
|  *   event / command is executed in all components - by simply awaiting the `triggerEvent()`. |  *   event / command is executed in all components - by simply awaiting the `triggerEvent()`. | ||||||
|  */ |  */ | ||||||
| export default class Component { | export default class Component { | ||||||
|  |     $widget!: JQuery<HTMLElement>; | ||||||
|     componentId: string; |     componentId: string; | ||||||
|     children: Component[]; |     children: Component[]; | ||||||
|     initialized: Promise<void> | null; |     initialized: Promise<void> | null; | ||||||
|   | |||||||
| @@ -3,9 +3,9 @@ import server from "./server.js"; | |||||||
|  |  | ||||||
| interface InitOptions { | interface InitOptions { | ||||||
|     $el: JQuery<HTMLElement>; |     $el: JQuery<HTMLElement>; | ||||||
|     attributeType: AttributeType | (() => AttributeType); |     attributeType?: AttributeType | (() => AttributeType); | ||||||
|     open: boolean; |     open: boolean; | ||||||
|     nameCallback: () => string; |     nameCallback?: () => string; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -54,7 +54,10 @@ async function initLabelValueAutocomplete({ $el, open, nameCallback }: InitOptio | |||||||
|         $el.autocomplete('destroy'); |         $el.autocomplete('destroy'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const attributeName = nameCallback(); |     let attributeName = ""; | ||||||
|  |     if (nameCallback) { | ||||||
|  |         attributeName = nameCallback(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (attributeName.trim() === "") { |     if (attributeName.trim() === "") { | ||||||
|         return; |         return; | ||||||
|   | |||||||
| @@ -10,6 +10,8 @@ import SpacedUpdate from "../../services/spaced_update.js"; | |||||||
| import utils from "../../services/utils.js"; | import utils from "../../services/utils.js"; | ||||||
| import shortcutService from "../../services/shortcuts.js"; | 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 FNote, { FNoteRow } from "../../entities/fnote.js"; | ||||||
| 
 | 
 | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="attr-detail"> | <div class="attr-detail"> | ||||||
| @@ -175,14 +177,14 @@ const TPL = ` | |||||||
| 
 | 
 | ||||||
| const DISPLAYED_NOTES = 10; | const DISPLAYED_NOTES = 10; | ||||||
| 
 | 
 | ||||||
| const ATTR_TITLES = { | const ATTR_TITLES: Record<string, string> = { | ||||||
|     "label": t('attribute_detail.label'), |     "label": t('attribute_detail.label'), | ||||||
|     "label-definition": t('attribute_detail.label_definition'), |     "label-definition": t('attribute_detail.label_definition'), | ||||||
|     "relation": t('attribute_detail.relation'), |     "relation": t('attribute_detail.relation'), | ||||||
|     "relation-definition": t('attribute_detail.relation_definition') |     "relation-definition": t('attribute_detail.relation_definition') | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const ATTR_HELP = { | const ATTR_HELP: Record<string, Record<string, string>> = { | ||||||
|     "label": { |     "label": { | ||||||
|         "disableVersioning": t('attribute_detail.disable_versioning'), |         "disableVersioning": t('attribute_detail.disable_versioning'), | ||||||
|         "calendarRoot": t('attribute_detail.calendar_root'), |         "calendarRoot": t('attribute_detail.calendar_root'), | ||||||
| @@ -266,7 +268,61 @@ const ATTR_HELP = { | |||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | interface AttributeDetailOpts { | ||||||
|  |     allAttributes: FAttribute[]; | ||||||
|  |     attribute: FAttribute; | ||||||
|  |     isOwned: boolean; | ||||||
|  |     x: number; | ||||||
|  |     y: number; | ||||||
|  |     focus: "name"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | interface SearchRelatedResponse { | ||||||
|  |     // TODO: Deduplicate once we split client from server.
 | ||||||
|  |     results: { | ||||||
|  |         noteId: string; | ||||||
|  |         notePathArray: string[]; | ||||||
|  |     }[]; | ||||||
|  |     count: number; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export default class AttributeDetailWidget extends NoteContextAwareWidget { | export default class AttributeDetailWidget extends NoteContextAwareWidget { | ||||||
|  | 
 | ||||||
|  |     private $title!: JQuery<HTMLElement>; | ||||||
|  |     private $inputName!: JQuery<HTMLElement>; | ||||||
|  |     private $inputValue!: JQuery<HTMLElement>; | ||||||
|  |     private $rowPromoted!: JQuery<HTMLElement>; | ||||||
|  |     private $inputPromoted!: JQuery<HTMLElement>; | ||||||
|  |     private $inputPromotedAlias!: JQuery<HTMLElement>; | ||||||
|  |     private $inputMultiplicity!: JQuery<HTMLElement>; | ||||||
|  |     private $inputInverseRelation!: JQuery<HTMLElement>; | ||||||
|  |     private $inputLabelType!: JQuery<HTMLElement>; | ||||||
|  |     private $inputTargetNote!: JQuery<HTMLElement>; | ||||||
|  |     private $inputNumberPrecision!: JQuery<HTMLElement>; | ||||||
|  |     private $inputInheritable!: JQuery<HTMLElement>; | ||||||
|  |     private $rowValue!: JQuery<HTMLElement>; | ||||||
|  |     private $rowMultiplicity!: JQuery<HTMLElement>; | ||||||
|  |     private $rowLabelType!: JQuery<HTMLElement>; | ||||||
|  |     private $rowNumberPrecision!: JQuery<HTMLElement>; | ||||||
|  |     private $rowInverseRelation!: JQuery<HTMLElement>; | ||||||
|  |     private $rowTargetNote!: JQuery<HTMLElement>; | ||||||
|  |     private $rowPromotedAlias!: JQuery<HTMLElement>; | ||||||
|  |     private $attrIsOwnedBy!: JQuery<HTMLElement>; | ||||||
|  |     private $attrSaveDeleteButtonContainer!: JQuery<HTMLElement>; | ||||||
|  |     private $closeAttrDetailButton!: JQuery<HTMLElement>; | ||||||
|  |     private $saveAndCloseButton!: JQuery<HTMLElement>; | ||||||
|  |     private $deleteButton!: JQuery<HTMLElement>; | ||||||
|  |     private $relatedNotesContainer!: JQuery<HTMLElement>; | ||||||
|  |     private $relatedNotesTitle!: JQuery<HTMLElement>; | ||||||
|  |     private $relatedNotesList!: JQuery<HTMLElement>; | ||||||
|  |     private $relatedNotesMoreNotes!: JQuery<HTMLElement>; | ||||||
|  |     private $attrHelp!: JQuery<HTMLElement>; | ||||||
|  | 
 | ||||||
|  |     private relatedNotesSpacedUpdate!: SpacedUpdate; | ||||||
|  |     private attribute!: FAttribute; | ||||||
|  |     private allAttributes!: FAttribute[]; | ||||||
|  |     private attrType!: ReturnType<AttributeDetailWidget["getAttrType"]>; | ||||||
|  | 
 | ||||||
|     async refresh() { |     async refresh() { | ||||||
|         // switching note/tab should close the widget
 |         // switching note/tab should close the widget
 | ||||||
| 
 | 
 | ||||||
| @@ -286,7 +342,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
| 
 | 
 | ||||||
|         this.$inputName = this.$widget.find('.attr-input-name'); |         this.$inputName = this.$widget.find('.attr-input-name'); | ||||||
|         this.$inputName.on('input', ev => { |         this.$inputName.on('input', ev => { | ||||||
|             if (!ev.originalEvent?.isComposing) { // https://github.com/zadam/trilium/pull/3812
 |             if (!(ev.originalEvent as KeyboardEvent)?.isComposing) { // https://github.com/zadam/trilium/pull/3812
 | ||||||
|                 this.userEditedAttribute(); |                 this.userEditedAttribute(); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| @@ -296,7 +352,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|         this.$inputName.on('focus', () => { |         this.$inputName.on('focus', () => { | ||||||
|             attributeAutocompleteService.initAttributeNameAutocomplete({ |             attributeAutocompleteService.initAttributeNameAutocomplete({ | ||||||
|                 $el: this.$inputName, |                 $el: this.$inputName, | ||||||
|                 attributeType: () => ['relation', 'relation-definition'].includes(this.attrType) ? 'relation' : 'label', |                 attributeType: () => ['relation', 'relation-definition'].includes(this.attrType || "") ? 'relation' : 'label', | ||||||
|                 open: true |                 open: true | ||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
| @@ -304,7 +360,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|         this.$rowValue = this.$widget.find('.attr-row-value'); |         this.$rowValue = this.$widget.find('.attr-row-value'); | ||||||
|         this.$inputValue = this.$widget.find('.attr-input-value'); |         this.$inputValue = this.$widget.find('.attr-input-value'); | ||||||
|         this.$inputValue.on('input', ev => { |         this.$inputValue.on('input', ev => { | ||||||
|             if (!ev.originalEvent?.isComposing) { // https://github.com/zadam/trilium/pull/3812
 |             if (!(ev.originalEvent as KeyboardEvent)?.isComposing) { // https://github.com/zadam/trilium/pull/3812
 | ||||||
|                 this.userEditedAttribute(); |                 this.userEditedAttribute(); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| @@ -314,7 +370,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|             attributeAutocompleteService.initLabelValueAutocomplete({ |             attributeAutocompleteService.initLabelValueAutocomplete({ | ||||||
|                 $el: this.$inputValue, |                 $el: this.$inputValue, | ||||||
|                 open: true, |                 open: true, | ||||||
|                 nameCallback: () => this.$inputName.val() |                 nameCallback: () => String(this.$inputName.val()) | ||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
| @@ -341,7 +397,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|         this.$rowInverseRelation = this.$widget.find('.attr-row-inverse-relation'); |         this.$rowInverseRelation = this.$widget.find('.attr-row-inverse-relation'); | ||||||
|         this.$inputInverseRelation = this.$widget.find('.attr-input-inverse-relation'); |         this.$inputInverseRelation = this.$widget.find('.attr-input-inverse-relation'); | ||||||
|         this.$inputInverseRelation.on('input', ev => { |         this.$inputInverseRelation.on('input', ev => { | ||||||
|             if (!ev.originalEvent?.isComposing) { // https://github.com/zadam/trilium/pull/3812
 |             if (!(ev.originalEvent as KeyboardEvent)?.isComposing) { // https://github.com/zadam/trilium/pull/3812
 | ||||||
|                 this.userEditedAttribute(); |                 this.userEditedAttribute(); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| @@ -403,7 +459,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async showAttributeDetail({ allAttributes, attribute, isOwned, x, y, focus }) { |     async showAttributeDetail({ allAttributes, attribute, isOwned, x, y, focus }: AttributeDetailOpts) { | ||||||
|         if (!attribute) { |         if (!attribute) { | ||||||
|             this.hide(); |             this.hide(); | ||||||
| 
 | 
 | ||||||
| @@ -418,11 +474,13 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|             this.attrType === 'label-definition' ? attribute.name.substr(6) |             this.attrType === 'label-definition' ? attribute.name.substr(6) | ||||||
|                 : (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) | ||||||
|             : {}; |             : {}; | ||||||
| 
 | 
 | ||||||
|         this.$title.text(ATTR_TITLES[this.attrType]); |         if (this.attrType) { | ||||||
|  |             this.$title.text(ATTR_TITLES[this.attrType]); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         this.allAttributes = allAttributes; |         this.allAttributes = allAttributes; | ||||||
|         this.attribute = attribute; |         this.attribute = attribute; | ||||||
| @@ -444,51 +502,53 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|                 .append(await linkService.createLink(attribute.noteId)) |                 .append(await linkService.createLink(attribute.noteId)) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         const disabledFn = (() => !isOwned ? "true" : undefined); | ||||||
|  | 
 | ||||||
|         this.$inputName |         this.$inputName | ||||||
|             .val(attrName) |             .val(attrName) | ||||||
|             .attr('readonly', () => !isOwned); |             .attr('readonly', disabledFn); | ||||||
| 
 | 
 | ||||||
|         this.$rowValue.toggle(this.attrType === 'label'); |         this.$rowValue.toggle(this.attrType === 'label'); | ||||||
|         this.$rowTargetNote.toggle(this.attrType === 'relation'); |         this.$rowTargetNote.toggle(this.attrType === 'relation'); | ||||||
| 
 | 
 | ||||||
|         this.$rowPromoted.toggle(['label-definition', 'relation-definition'].includes(this.attrType)); |         this.$rowPromoted.toggle(['label-definition', 'relation-definition'].includes(this.attrType || "")); | ||||||
|         this.$inputPromoted |         this.$inputPromoted | ||||||
|             .prop("checked", !!definition.isPromoted) |             .prop("checked", !!definition.isPromoted) | ||||||
|             .attr('disabled', () => !isOwned); |             .attr('disabled', disabledFn); | ||||||
| 
 | 
 | ||||||
|         this.$rowPromotedAlias.toggle(!!definition.isPromoted); |         this.$rowPromotedAlias.toggle(!!definition.isPromoted); | ||||||
|         this.$inputPromotedAlias |         this.$inputPromotedAlias | ||||||
|             .val(definition.promotedAlias) |             .val(definition.promotedAlias || "") | ||||||
|             .attr('disabled', () => !isOwned); |             .attr('disabled', disabledFn); | ||||||
| 
 | 
 | ||||||
|         this.$rowMultiplicity.toggle(['label-definition', 'relation-definition'].includes(this.attrType)); |         this.$rowMultiplicity.toggle(['label-definition', 'relation-definition'].includes(this.attrType || "")); | ||||||
|         this.$inputMultiplicity |         this.$inputMultiplicity | ||||||
|             .val(definition.multiplicity) |             .val(definition.multiplicity || "") | ||||||
|             .attr('disabled', () => !isOwned); |             .attr('disabled', disabledFn); | ||||||
| 
 | 
 | ||||||
|         this.$rowLabelType.toggle(this.attrType === 'label-definition'); |         this.$rowLabelType.toggle(this.attrType === 'label-definition'); | ||||||
|         this.$inputLabelType |         this.$inputLabelType | ||||||
|             .val(definition.labelType) |             .val(definition.labelType || "") | ||||||
|             .attr('disabled', () => !isOwned); |             .attr('disabled', disabledFn); | ||||||
| 
 | 
 | ||||||
|         this.$rowNumberPrecision.toggle(this.attrType === 'label-definition' && definition.labelType === 'number'); |         this.$rowNumberPrecision.toggle(this.attrType === 'label-definition' && definition.labelType === 'number'); | ||||||
|         this.$inputNumberPrecision |         this.$inputNumberPrecision | ||||||
|             .val(definition.numberPrecision) |             .val(definition.numberPrecision || "") | ||||||
|             .attr('disabled', () => !isOwned); |             .attr('disabled', disabledFn); | ||||||
| 
 | 
 | ||||||
|         this.$rowInverseRelation.toggle(this.attrType === 'relation-definition'); |         this.$rowInverseRelation.toggle(this.attrType === 'relation-definition'); | ||||||
|         this.$inputInverseRelation |         this.$inputInverseRelation | ||||||
|             .val(definition.inverseRelation) |             .val(definition.inverseRelation || "") | ||||||
|             .attr('disabled', () => !isOwned); |             .attr('disabled', disabledFn); | ||||||
| 
 | 
 | ||||||
|         if (attribute.type === 'label') { |         if (attribute.type === 'label') { | ||||||
|             this.$inputValue |             this.$inputValue | ||||||
|                 .val(attribute.value) |                 .val(attribute.value) | ||||||
|                 .attr('readonly', () => !isOwned); |                 .attr('readonly', disabledFn); | ||||||
|         } |         } | ||||||
|         else if (attribute.type === 'relation') { |         else if (attribute.type === 'relation') { | ||||||
|             this.$inputTargetNote |             this.$inputTargetNote | ||||||
|                 .attr('readonly', () => !isOwned) |                 .attr('readonly', disabledFn) | ||||||
|                 .val("") |                 .val("") | ||||||
|                 .setSelectedNotePath(""); |                 .setSelectedNotePath(""); | ||||||
| 
 | 
 | ||||||
| @@ -505,23 +565,27 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
| 
 | 
 | ||||||
|         this.$inputInheritable |         this.$inputInheritable | ||||||
|             .prop("checked", !!attribute.isInheritable) |             .prop("checked", !!attribute.isInheritable) | ||||||
|             .attr('disabled', () => !isOwned); |             .attr('disabled', disabledFn); | ||||||
| 
 | 
 | ||||||
|         this.updateHelp(); |         this.updateHelp(); | ||||||
| 
 | 
 | ||||||
|         this.toggleInt(true); |         this.toggleInt(true); | ||||||
| 
 | 
 | ||||||
|         const offset = this.parent.$widget.offset(); |         const offset = this.parent?.$widget.offset() || { top: 0, left: 0 }; | ||||||
|         const detPosition = this.getDetailPosition(x, offset); |         const detPosition = this.getDetailPosition(x, offset); | ||||||
|  |         const outerHeight = this.$widget.outerHeight(); | ||||||
|  |         const height = $(window).height(); | ||||||
| 
 | 
 | ||||||
|         this.$widget |         if (detPosition && outerHeight && height) { | ||||||
|             .css("left", detPosition.left) |             this.$widget | ||||||
|             .css("right", detPosition.right) |                 .css("left", detPosition.left) | ||||||
|             .css("top", y - offset.top + 70) |                 .css("right", detPosition.right) | ||||||
|             .css("max-height", |                 .css("top", y - offset.top + 70) | ||||||
|                 this.$widget.outerHeight() + y > $(window).height() - 50 |                 .css("max-height", | ||||||
|                     ? $(window).height() - y - 50 |                     outerHeight + y > height - 50 | ||||||
|                     : 10000); |                         ? height - y - 50 | ||||||
|  |                         : 10000); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         if (focus === 'name') { |         if (focus === 'name') { | ||||||
|             this.$inputName |             this.$inputName | ||||||
| @@ -530,16 +594,21 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     getDetailPosition(x, offset) { |     getDetailPosition(x: number, offset: { left: number }) { | ||||||
|         let left = x - offset.left - this.$widget.outerWidth() / 2; |         const outerWidth = this.$widget.outerWidth(); | ||||||
|         let right = ""; |         if (!outerWidth) { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let left: number | string = x - offset.left - outerWidth / 2; | ||||||
|  |         let right: number | string = ""; | ||||||
| 
 | 
 | ||||||
|         if (left < 0) { |         if (left < 0) { | ||||||
|             left = 10; |             left = 10; | ||||||
|         } else { |         } else { | ||||||
|             const rightEdge = left + this.$widget.outerWidth(); |             const rightEdge = left + outerWidth; | ||||||
| 
 | 
 | ||||||
|             if (rightEdge > this.parent.$widget.outerWidth() - 10) { |             if (rightEdge > outerWidth - 10) { | ||||||
|                 left = ""; |                 left = ""; | ||||||
|                 right = 10; |                 right = 10; | ||||||
|             } |             } | ||||||
| @@ -571,9 +640,10 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     updateHelp() { |     updateHelp() { | ||||||
|         const attrName = this.$inputName.val(); |         const attrName = String(this.$inputName.val()); | ||||||
| 
 | 
 | ||||||
|         if (this.attrType in ATTR_HELP && attrName in ATTR_HELP[this.attrType]) { |         if (this.attrType && this.attrType in ATTR_HELP && | ||||||
|  |             attrName && attrName in ATTR_HELP[this.attrType]) { | ||||||
|             this.$attrHelp |             this.$attrHelp | ||||||
|                 .empty() |                 .empty() | ||||||
|                 .append($("<td colspan=2>") |                 .append($("<td colspan=2>") | ||||||
| @@ -589,7 +659,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async updateRelatedNotes() { |     async updateRelatedNotes() { | ||||||
|         let { results, count } = await server.post('search-related', this.attribute); |         let { results, count } = await server.post<SearchRelatedResponse>('search-related', this.attribute); | ||||||
| 
 | 
 | ||||||
|         for (const res of results) { |         for (const res of results) { | ||||||
|             res.noteId = res.notePathArray[res.notePathArray.length - 1]; |             res.noteId = res.notePathArray[res.notePathArray.length - 1]; | ||||||
| @@ -626,7 +696,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     getAttrType(attribute) { |     getAttrType(attribute: FAttribute) { | ||||||
|         if (attribute.type === 'label') { |         if (attribute.type === 'label') { | ||||||
|             if (attribute.name.startsWith('label:')) { |             if (attribute.name.startsWith('label:')) { | ||||||
|                 return "label-definition"; |                 return "label-definition"; | ||||||
| @@ -645,7 +715,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     updateAttributeInEditor() { |     updateAttributeInEditor() { | ||||||
|         let attrName = this.$inputName.val(); |         let attrName = String(this.$inputName.val()); | ||||||
| 
 | 
 | ||||||
|         if (!utils.isValidAttributeName(attrName)) { |         if (!utils.isValidAttributeName(attrName)) { | ||||||
|             // invalid characters are simply ignored (from user perspective they are not even entered)
 |             // invalid characters are simply ignored (from user perspective they are not even entered)
 | ||||||
| @@ -663,14 +733,14 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|         this.attribute.name = attrName; |         this.attribute.name = attrName; | ||||||
|         this.attribute.isInheritable = this.$inputInheritable.is(":checked"); |         this.attribute.isInheritable = this.$inputInheritable.is(":checked"); | ||||||
| 
 | 
 | ||||||
|         if (this.attrType.endsWith('-definition')) { |         if (this.attrType?.endsWith('-definition')) { | ||||||
|             this.attribute.value = this.buildDefinitionValue(); |             this.attribute.value = this.buildDefinitionValue(); | ||||||
|         } |         } | ||||||
|         else if (this.attrType === 'relation') { |         else if (this.attrType === 'relation') { | ||||||
|             this.attribute.value = this.$inputTargetNote.getSelectedNoteId(); |             this.attribute.value = this.$inputTargetNote.getSelectedNoteId() || ""; | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             this.attribute.value = this.$inputValue.val(); |             this.attribute.value = String(this.$inputValue.val()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         this.triggerCommand('updateAttributeList', { attributes: this.allAttributes }); |         this.triggerCommand('updateAttributeList', { attributes: this.allAttributes }); | ||||||
| @@ -695,10 +765,10 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|             if (this.$inputLabelType.val() === 'number' && this.$inputNumberPrecision.val() !== '') { |             if (this.$inputLabelType.val() === 'number' && this.$inputNumberPrecision.val() !== '') { | ||||||
|                 props.push(`precision=${this.$inputNumberPrecision.val()}`); |                 props.push(`precision=${this.$inputNumberPrecision.val()}`); | ||||||
|             } |             } | ||||||
|         } else if (this.attrType === 'relation-definition' && this.$inputInverseRelation.val().trim().length > 0) { |         } else if (this.attrType === 'relation-definition' && String(this.$inputInverseRelation.val())?.trim().length > 0) { | ||||||
|             const inverseRelationName = this.$inputInverseRelation.val(); |             const inverseRelationName = this.$inputInverseRelation.val(); | ||||||
| 
 | 
 | ||||||
|             props.push(`inverse=${utils.filterAttributeName(inverseRelationName)}`); |             props.push(`inverse=${utils.filterAttributeName(String(inverseRelationName))}`); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         this.$rowNumberPrecision.toggle( |         this.$rowNumberPrecision.toggle( | ||||||
| @@ -714,7 +784,7 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget { | |||||||
|         this.toggleInt(false); |         this.toggleInt(false); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     createLink(noteId) { |     createLink(noteId: string) { | ||||||
|         return $("<a>", { |         return $("<a>", { | ||||||
|             href: `#root/${noteId}`, |             href: `#root/${noteId}`, | ||||||
|             class: 'reference-link' |             class: 'reference-link' | ||||||
| @@ -13,7 +13,6 @@ class BasicWidget extends Component { | |||||||
|     private classes: string[]; |     private classes: string[]; | ||||||
|     private childPositionCounter: number; |     private childPositionCounter: number; | ||||||
|     private cssEl?: string; |     private cssEl?: string; | ||||||
|     protected $widget!: JQuery<HTMLElement>; |  | ||||||
|     _noteId!: string; |     _noteId!: string; | ||||||
|  |  | ||||||
|     constructor() { |     constructor() { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user