diff --git a/src/public/app/widgets/attribute_editor.js b/src/public/app/widgets/attribute_editor.js index 382a2427a..018967198 100644 --- a/src/public/app/widgets/attribute_editor.js +++ b/src/public/app/widgets/attribute_editor.js @@ -45,13 +45,18 @@ const TPL = ` border: 1px solid var(--main-border-color); border-radius: 2px; } + + .attribute-errors { + color: red; + }
-
+ + `; @@ -171,6 +176,12 @@ const editorConfig = { }; export default class AttributeEditorWidget extends TabAwareWidget { + constructor(attributeDetailWidget) { + super(); + + this.attributeDetailWidget = attributeDetailWidget; + } + doRender() { this.$widget = $(TPL); this.$editor = this.$widget.find('.attribute-list-editor'); @@ -190,76 +201,83 @@ export default class AttributeEditorWidget extends TabAwareWidget { }); this.$addNewAttributeButton = this.$widget.find('.add-new-attribute-button'); - this.$addNewAttributeButton.on('click', 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: async ({command}) => { - const attrs = this.parseAttributes(); + this.$addNewAttributeButton.on('click', e => this.addNewAttribute(e)); - if (!attrs) { - return; - } + this.$saveAttributesButton = this.$widget.find('.save-attributes-button'); + this.$saveAttributesButton.on('click', () => this.save()); - let type, name; + this.$errors = this.$widget.find('.attribute-errors'); + } - if (command === 'addNewLabel') { - type = 'label'; - name = 'fillName'; - } - else if (command === 'addNewRelation') { - type = 'relation'; - name = 'fillName'; - } - else if (command === 'addNewLabelDefinition') { - type = 'label'; - name = 'label:fillName'; - } - else if (command === 'addNewRelationDefinition') { - type = 'label'; - name = 'relation:fillName'; - } - else { - return; - } - - attrs.push({ - type, - name, - value: '', - isInheritable: false - }); - - await this.renderOwnedAttributes(attrs); - - 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); - } - }); + 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) }); } + async handleAddNewAttributeCommand(command) { + const attrs = this.parseAttributes(); + + if (!attrs) { + return; + } + + let type, name; + + if (command === 'addNewLabel') { + type = 'label'; + name = 'fillName'; + } else if (command === 'addNewRelation') { + type = 'relation'; + name = 'fillName'; + } else if (command === 'addNewLabelDefinition') { + type = 'label'; + name = 'label:fillName'; + } else if (command === 'addNewRelationDefinition') { + type = 'label'; + name = 'relation:fillName'; + } else { + return; + } + + attrs.push({ + type, + name, + value: '', + isInheritable: false + }); + + await this.renderOwnedAttributes(attrs); + + 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); + } + async save() { + this.$saveAttributesButton.fadeOut(); + const attributes = this.parseAttributes(); if (attributes) { @@ -274,11 +292,7 @@ export default class AttributeEditorWidget extends TabAwareWidget { return attrs; } catch (e) { - this.$widget.attr("title", e.message); - this.$widget.addClass("error"); - - this.$ownedExpander.addClass("error"); - this.$ownedExpanderText.text(e.message); + this.$errors.show().text(e.message); } } @@ -300,7 +314,16 @@ export default class AttributeEditorWidget extends TabAwareWidget { } dataChanged() { - console.log("Data changed"); + if (this.lastSavedContent === this.textEditor.getData()) { + this.$saveAttributesButton.fadeOut(); + } + else { + this.$saveAttributesButton.fadeIn(); + } + + if (this.$errors.is(":visible")) { + this.$errors.slideUp(); + } } async handleEditorClick(e) { @@ -309,7 +332,15 @@ export default class AttributeEditorWidget extends TabAwareWidget { if (pos && pos.textNode && pos.textNode.data) { const clickIndex = this.getClickIndex(pos); - const parsedAttrs = attributesParser.lexAndParse(this.textEditor.getData(), true); + 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; + } let matchedAttr = null; @@ -370,7 +401,7 @@ export default class AttributeEditorWidget extends TabAwareWidget { await this.renderOwnedAttributes(note.getOwnedAttributes()); } - async renderOwnedAttributes(ownedAttributes) { + async renderOwnedAttributes(ownedAttributes, ) { const $attributesContainer = $("
"); for (const attribute of ownedAttributes) { @@ -378,6 +409,10 @@ export default class AttributeEditorWidget extends TabAwareWidget { } this.textEditor.setData($attributesContainer.html()); + + this.lastSavedContent = this.textEditor.getData(); + + this.$saveAttributesButton.fadeOut(0); } async focusOnAttributesEvent({tabId}) { @@ -386,7 +421,7 @@ export default class AttributeEditorWidget extends TabAwareWidget { } } - updateAttributeListCommand({attributes}) { + updateAttributeList(attributes) { this.renderOwnedAttributes(attributes); } } diff --git a/src/public/app/widgets/attribute_list.js b/src/public/app/widgets/attribute_list.js index 04d50c866..6f63d2461 100644 --- a/src/public/app/widgets/attribute_list.js +++ b/src/public/app/widgets/attribute_list.js @@ -93,8 +93,8 @@ export default class AttributeListWidget extends TabAwareWidget { constructor() { super(); - this.attributeEditorWidget = new AttributeEditorWidget().setParent(this); this.attributeDetailWidget = new AttributeDetailWidget().setParent(this); + this.attributeEditorWidget = new AttributeEditorWidget(this.attributeDetailWidget).setParent(this); this.child(this.attributeEditorWidget, this.attributeDetailWidget); } @@ -183,4 +183,8 @@ export default class AttributeListWidget extends TabAwareWidget { attributeRenderer.renderAttribute(attribute, $span, false); } } + + updateAttributeListCommand({attributes}) { + this.attributeEditorWidget.updateAttributeList(attributes); + } } diff --git a/src/public/app/widgets/promoted_attributes.js b/src/public/app/widgets/promoted_attributes.js index e6db996dc..024649afb 100644 --- a/src/public/app/widgets/promoted_attributes.js +++ b/src/public/app/widgets/promoted_attributes.js @@ -54,7 +54,7 @@ export default class PromotedAttributesWidget extends TabAwareWidget { const definitionType = definitionAttr.name.startsWith('label:') ? 'label' : 'relation'; const valueName = definitionAttr.name.substr(definitionType.length + 1); - let valueAttrs = attributes.filter(el => el.name === definitionAttr.name && el.type === definitionType); + let valueAttrs = attributes.filter(el => el.name === valueName && el.type === 'label'); if (valueAttrs.length === 0) { valueAttrs.push({