promoted attributes are now part of attr list and also responsive

This commit is contained in:
zadam 2020-07-25 00:06:49 +02:00
parent b60efbbf5a
commit 2217c5a3e0
3 changed files with 138 additions and 113 deletions

View File

@ -136,7 +136,6 @@ export default class DesktopMainWindowLayout {
.child(new NoteActionsWidget().hideInZenMode()) .child(new NoteActionsWidget().hideInZenMode())
) )
.child(new TabCachingWidget(() => new AttributeListWidget())) .child(new TabCachingWidget(() => new AttributeListWidget()))
.child(new TabCachingWidget(() => new PromotedAttributesWidget()))
.child(new TabCachingWidget(() => new NoteDetailWidget())) .child(new TabCachingWidget(() => new NoteDetailWidget()))
.child(...this.customWidgets.get('center-pane')) .child(...this.customWidgets.get('center-pane'))
) )

View File

@ -3,6 +3,7 @@ import AttributeDetailWidget from "./attribute_detail.js";
import attributeRenderer from "../services/attribute_renderer.js"; import attributeRenderer from "../services/attribute_renderer.js";
import AttributeEditorWidget from "./attribute_editor.js"; import AttributeEditorWidget from "./attribute_editor.js";
import options from '../services/options.js'; import options from '../services/options.js';
import PromotedAttributesWidget from "./promoted_attributes.js";
const TPL = ` const TPL = `
<div class="attribute-list"> <div class="attribute-list">
@ -63,7 +64,18 @@ const TPL = `
} }
</style> </style>
<div class="attr-expander attr-owned-expander"> <div class="attr-expander attr-promoted-expander">
<hr class="w-100">
<div class="attr-expander-text">Promoted attributes</div>
<hr class="w-100">
</div>
<div class="all-attr-wrapper">
<div class="promoted-attributes-placeholder"></div>
<div class="attr-expander attr-owned-and-inherited-expander">
<hr class="w-100"> <hr class="w-100">
<div class="attr-expander-text"></div> <div class="attr-expander-text"></div>
@ -71,7 +83,7 @@ const TPL = `
<hr class="w-100"> <hr class="w-100">
</div> </div>
<div class="attr-display"> <div class="owned-and-inherited-wrapper">
<div class="attr-editor-placeholder"></div> <div class="attr-editor-placeholder"></div>
<hr class="w-100 attr-inherited-empty-expander" style="margin-bottom: 10px;"> <hr class="w-100 attr-inherited-empty-expander" style="margin-bottom: 10px;">
@ -86,7 +98,7 @@ const TPL = `
<div class="inherited-attributes"></div> <div class="inherited-attributes"></div>
</div> </div>
</div>
</div> </div>
`; `;
@ -94,21 +106,33 @@ export default class AttributeListWidget extends TabAwareWidget {
constructor() { constructor() {
super(); super();
this.promotedAttributesWidget = new PromotedAttributesWidget().setParent(this);
this.attributeDetailWidget = new AttributeDetailWidget().setParent(this); this.attributeDetailWidget = new AttributeDetailWidget().setParent(this);
this.attributeEditorWidget = new AttributeEditorWidget(this.attributeDetailWidget).setParent(this); this.attributeEditorWidget = new AttributeEditorWidget(this.attributeDetailWidget).setParent(this);
this.child(this.attributeEditorWidget, this.attributeDetailWidget); this.child(this.promotedAttributesWidget, this.attributeEditorWidget, this.attributeDetailWidget);
} }
doRender() { doRender() {
this.$widget = $(TPL); this.$widget = $(TPL);
this.$attrDisplay = this.$widget.find('.attr-display'); this.$promotedExpander = this.$widget.find('.attr-promoted-expander');
this.$attrDisplay.toggle(options.is('attributeListExpanded')); this.$allAttrWrapper = this.$widget.find('.all-attr-wrapper');
this.$ownedExpander = this.$widget.find('.attr-owned-expander'); this.$promotedExpander.on('click', async () => {
if (this.$allAttrWrapper.is(":visible")) {
this.$allAttrWrapper.slideUp(200);
} else {
this.$allAttrWrapper.slideDown(200);
}
});
this.$ownedAndInheritedWrapper = this.$widget.find('.owned-and-inherited-wrapper');
this.$ownedAndInheritedWrapper.toggle(options.is('attributeListExpanded'));
this.$ownedExpander = this.$widget.find('.attr-owned-and-inherited-expander');
this.$ownedExpander.on('click', async () => { this.$ownedExpander.on('click', async () => {
const collapse = this.$attrDisplay.is(":visible"); const collapse = this.$ownedAndInheritedWrapper.is(":visible");
await options.save('attributeListExpanded', !collapse); await options.save('attributeListExpanded', !collapse);
@ -133,6 +157,7 @@ export default class AttributeListWidget extends TabAwareWidget {
this.$inheritedEmptyExpander = this.$widget.find('.attr-inherited-empty-expander'); this.$inheritedEmptyExpander = this.$widget.find('.attr-inherited-empty-expander');
this.$widget.find('.promoted-attributes-placeholder').replaceWith(this.promotedAttributesWidget.render());
this.$widget.find('.attr-editor-placeholder').replaceWith(this.attributeEditorWidget.render()); this.$widget.find('.attr-editor-placeholder').replaceWith(this.attributeEditorWidget.render());
this.$widget.append(this.attributeDetailWidget.render()); this.$widget.append(this.attributeDetailWidget.render());
} }
@ -199,10 +224,9 @@ export default class AttributeListWidget extends TabAwareWidget {
*/ */
attributeListCollapsedStateChangedEvent({collapse}) { attributeListCollapsedStateChangedEvent({collapse}) {
if (collapse) { if (collapse) {
this.$attrDisplay.slideUp(200); this.$ownedAndInheritedWrapper.slideUp(200);
} } else {
else { this.$ownedAndInheritedWrapper.slideDown(200);
this.$attrDisplay.slideDown(200);
} }
} }
} }

View File

@ -5,34 +5,39 @@ import noteAutocompleteService from "../services/note_autocomplete.js";
import TabAwareWidget from "./tab_aware_widget.js"; import TabAwareWidget from "./tab_aware_widget.js";
const TPL = ` const TPL = `
<div class="promoted-attributes-wrapper"> <div>
<style> <style>
.promoted-attributes-wrapper { .promoted-attributes-container {
margin: auto; margin: auto;
/* setting the display to block since "table" doesn't support scrolling */ display: flex;
display: block; flex-direction: row;
/** flex-basis: content; - use once "content" is implemented by chrome */
flex-shrink: 0; flex-shrink: 0;
flex-grow: 0; flex-grow: 0;
justify-content: space-evenly;
overflow: auto; overflow: auto;
max-height: 400px; max-height: 400px;
flex-wrap: wrap;
} }
.promoted-attributes td, .promoted-attributes th { .promoted-attribute-cell {
padding: 5px; display: flex;
min-width: 50px; /* otherwise checkboxes can collapse into 0 width (if there are only checkboxes) */ align-items: center;
margin: 10px;
}
.promoted-attribute-cell div.input-group {
margin-left: 10px;
} }
</style> </style>
<table class="promoted-attributes"></table> <div class="promoted-attributes-container"></div>
</div> </div>
`; `;
export default class PromotedAttributesWidget extends TabAwareWidget { export default class PromotedAttributesWidget extends TabAwareWidget {
doRender() { doRender() {
this.$widget = $(TPL); this.$widget = $(TPL);
this.$container = this.$widget.find(".promoted-attributes-container");
this.$container = this.$widget.find(".promoted-attributes");
} }
async refreshWithNote(note) { async refreshWithNote(note) {
@ -48,9 +53,9 @@ export default class PromotedAttributesWidget extends TabAwareWidget {
return def && def.isPromoted; return def && def.isPromoted;
}); });
if (promoted.length > 0 && !note.hasLabel('hidePromotedAttributes')) { const cells = [];
const $tbody = $("<tbody>");
if (promoted.length > 0 && !note.hasLabel('hidePromotedAttributes')) {
for (const definitionAttr of promoted) { for (const definitionAttr of promoted) {
const definitionType = definitionAttr.name.startsWith('label:') ? 'label' : 'relation'; const definitionType = definitionAttr.name.startsWith('label:') ? 'label' : 'relation';
const valueName = definitionAttr.name.substr(definitionType.length + 1); const valueName = definitionAttr.name.substr(definitionType.length + 1);
@ -71,15 +76,15 @@ export default class PromotedAttributesWidget extends TabAwareWidget {
} }
for (const valueAttr of valueAttrs) { for (const valueAttr of valueAttrs) {
const $tr = await this.createPromotedAttributeRow(definitionAttr, valueAttr, valueName); const $cell = await this.createPromotedAttributeCell(definitionAttr, valueAttr, valueName);
$tbody.append($tr); cells.push($cell);
} }
} }
// we replace the whole content in one step so there can't be any race conditions // we replace the whole content in one step so there can't be any race conditions
// (previously we saw promoted attributes doubling) // (previously we saw promoted attributes doubling)
this.$container.empty().append($tbody); this.$container.empty().append(...cells);
this.toggleInt(true); this.toggleInt(true);
} }
else { else {
@ -89,10 +94,9 @@ export default class PromotedAttributesWidget extends TabAwareWidget {
return attributes; return attributes;
} }
async createPromotedAttributeRow(definitionAttr, valueAttr, valueName) { async createPromotedAttributeCell(definitionAttr, valueAttr, valueName) {
const definition = definitionAttr.getDefinition(); const definition = definitionAttr.getDefinition();
const $tr = $("<tr>");
const $labelCell = $("<th>").append(valueName);
const $input = $("<input>") const $input = $("<input>")
.prop("tabindex", 200 + definitionAttr.position) .prop("tabindex", 200 + definitionAttr.position)
.prop("attribute-id", valueAttr.noteId === this.noteId ? valueAttr.attributeId : '') // if not owned, we'll force creation of a new attribute instead of updating the inherited one .prop("attribute-id", valueAttr.noteId === this.noteId ? valueAttr.attributeId : '') // if not owned, we'll force creation of a new attribute instead of updating the inherited one
@ -103,16 +107,14 @@ export default class PromotedAttributesWidget extends TabAwareWidget {
.addClass("promoted-attribute-input") .addClass("promoted-attribute-input")
.on('change', event => this.promotedAttributeChanged(event)); .on('change', event => this.promotedAttributeChanged(event));
const $inputCell = $("<td>").append($("<div>").addClass("input-group").append($input)); const $actionCell = $("<div>");
const $actionCell = $("<td>");
const $multiplicityCell = $("<td>") const $multiplicityCell = $("<td>")
.addClass("multiplicity") .addClass("multiplicity")
.attr("nowrap", true); .attr("nowrap", true);
$tr const $wrapper = $('<div class="promoted-attribute-cell">')
.append($labelCell) .append($("<strong>").text(valueName))
.append($inputCell) .append($("<div>").addClass("input-group").append($input))
.append($actionCell) .append($actionCell)
.append($multiplicityCell); .append($multiplicityCell);
@ -210,14 +212,14 @@ export default class PromotedAttributesWidget extends TabAwareWidget {
.addClass("bx bx-plus pointer") .addClass("bx bx-plus pointer")
.prop("title", "Add new attribute") .prop("title", "Add new attribute")
.on('click', async () => { .on('click', async () => {
const $new = await this.createPromotedAttributeRow(definitionAttr, { const $new = await this.createPromotedAttributeCell(definitionAttr, {
attributeId: "", attributeId: "",
type: valueAttr.type, type: valueAttr.type,
name: definitionAttr.name, name: definitionAttr.name,
value: "" value: ""
}); });
$tr.after($new); $wrapper.after($new);
$new.find('input').trigger('focus'); $new.find('input').trigger('focus');
}); });
@ -230,13 +232,13 @@ export default class PromotedAttributesWidget extends TabAwareWidget {
await server.remove("notes/" + this.noteId + "/attributes/" + valueAttr.attributeId, this.componentId); await server.remove("notes/" + this.noteId + "/attributes/" + valueAttr.attributeId, this.componentId);
} }
$tr.remove(); $wrapper.remove();
}); });
$multiplicityCell.append(addButton).append(" &nbsp;").append(removeButton); $multiplicityCell.append(addButton).append(" &nbsp;").append(removeButton);
} }
return $tr; return $wrapper;
} }
async promotedAttributeChanged(event) { async promotedAttributeChanged(event) {