Change the layouting of wp-attribute-groups

Attribute groups were positioned with CSS `column-count` values, which
is normally used for getting columns in longform text. However, this
caused errors in the past[1] and a new layouting error in Firefox now.

This commit changes the layouting to use CSS Flexbox, which allows us
to get rid of a lot of legacy stuff.

Adresses https://community.openproject.org/projects/openproject/work_packages/44846/activity

[1] https://community.openproject.org/projects/openproject/work_packages/31614/activity
fix/44846-custom-field-multi-select
Benjamin Bädorf 2 years ago
parent aa973e5e13
commit f703e4324e
No known key found for this signature in database
GPG Key ID: 069CA2D117AB5CCF
  1. 25
      frontend/src/app/features/work-packages/components/wp-form-group/wp-attribute-group.component.sass
  2. 44
      frontend/src/app/features/work-packages/components/wp-form-group/wp-attribute-group.component.ts
  3. 57
      frontend/src/app/features/work-packages/components/wp-form-group/wp-attribute-group.template.html
  4. 15
      frontend/src/app/features/work-packages/components/wp-single-view/wp-single-view.html
  5. 1
      frontend/src/app/shared/components/fields/edit/field/editable-attribute-field.component.ts
  6. 15
      frontend/src/global_styles/content/work_packages/single_view/_single_view.sass

@ -0,0 +1,25 @@
@import "src/assets/sass/helpers"
.wp-attribute-group
display: flex
flex-direction: row
flex-wrap: wrap
// We want a margin between items, but don't know if any one item is on the right,
// the left, or spanning both columns. The easy way to get a gutter is to give
// *all* elements margins on both sides, and then negating this margin on the parent.
// This also explains all of the + and - xrem calc() values below.
margin: 0 -1 * $spot-spacing-1_5
width: calc(100% + #{$spot-spacing-3})
&--attribute
flex-basis: calc(100% - #{$spot-spacing-3})
flex-grow: 0
flex-shrink: 0
margin: 0 $spot-spacing-1_5
@media screen and (min-width: 92rem), print
flex-basis: calc(50% - #{$spot-spacing-3})
&_span-all
flex-basis: calc(100% - #{$spot-spacing-3})

@ -27,14 +27,12 @@
//++
import {
Component, Injector, Input, AfterViewInit,
Component, HostBinding, Injector, Input, ViewEncapsulation,
} from '@angular/core';
import { I18nService } from 'core-app/core/i18n/i18n.service';
import { WorkPackageResource } from 'core-app/features/hal/resources/work-package-resource';
import { EditFormComponent } from 'core-app/shared/components/fields/edit/edit-form/edit-form.component';
import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin';
import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import {
FieldDescriptor,
GroupDescriptor,
@ -43,8 +41,12 @@ import {
@Component({
selector: 'wp-attribute-group',
templateUrl: './wp-attribute-group.template.html',
styleUrls: ['./wp-attribute-group.component.sass'],
encapsulation: ViewEncapsulation.None,
})
export class WorkPackageFormAttributeGroupComponent extends UntilDestroyedMixin implements AfterViewInit {
export class WorkPackageFormAttributeGroupComponent extends UntilDestroyedMixin {
@HostBinding('class.wp-attribute-group') className = true;
@Input() public workPackage:WorkPackageResource;
@Input() public group:GroupDescriptor;
@ -55,20 +57,6 @@ export class WorkPackageFormAttributeGroupComponent extends UntilDestroyedMixin
super();
}
ngAfterViewInit() {
setTimeout(() => this.fixColumns());
// Listen to resize event and fix column start again
fromEvent(window, 'resize', { passive: true })
.pipe(
this.untilDestroyed(),
debounceTime(250),
)
.subscribe(() => {
this.fixColumns();
});
}
public trackByName(_index:number, elem:{ name:string }) {
return elem.name;
}
@ -88,24 +76,4 @@ export class WorkPackageFormAttributeGroupComponent extends UntilDestroyedMixin
}
return name;
}
/**
* Fix the top of the columns after view has been loaded
* to prevent columns from repositioning (e.g. when editing multi-select fields)
*/
private fixColumns() {
let lastOffset = 0;
// Find corresponding HTML of attribute fields for each group
const htmlAttributes = jQuery(`div.attributes-group:contains(${this.group.name})`).find('.attributes-key-value');
htmlAttributes.each(function () {
const offset = jQuery(this).position().top;
if (offset < lastOffset) {
// Fix position of the column start
jQuery(this).addClass('-column-start');
}
lastOffset = offset;
});
}
}

@ -1,27 +1,32 @@
<div class="-columns-2">
<div class="attributes-key-value"
[ngClass]="{'-span-all-columns': descriptor.spanAll }"
*ngFor="let descriptor of group.members; trackBy:trackByName">
<ng-template [ngIf]="!shouldHideField(descriptor)">
<div
class="attributes-key-value--key"
*ngIf="!descriptor.multiple && descriptor.field">
<wp-replacement-label [fieldName]="descriptor.name">
{{ descriptor.label }}
<span class="required"
*ngIf="descriptor.field!.required && descriptor.field!.writable"> *</span>
</wp-replacement-label>
<attribute-help-text [attribute]="descriptor.name" [attributeScope]="'WorkPackage'"></attribute-help-text>
</div>
<div *ngIf="!descriptor.multiple && descriptor.field"
class="attributes-key-value--value-container">
<op-editable-attribute-field [ngClass]="{'wp-edit-formattable-field': descriptor.field!.isFormattable }"
[resource]="workPackage"
[isDropTarget]="descriptor.field!.isFormattable"
[fieldName]="fieldName(descriptor.name)">
</op-editable-attribute-field>
</div>
</ng-template>
</div>
<div
class="wp-attribute-group--attribute attributes-key-value"
[ngClass]="{'wp-attribute-group--attribute_span-all': descriptor.spanAll }"
*ngFor="let descriptor of group.members; trackBy:trackByName"
>
<ng-template [ngIf]="!shouldHideField(descriptor)">
<div
class="attributes-key-value--key"
*ngIf="!descriptor.multiple && descriptor.field"
>
<wp-replacement-label [fieldName]="descriptor.name">
{{ descriptor.label }}
<span
class="required"
*ngIf="descriptor.field!.required && descriptor.field!.writable"
>*</span>
</wp-replacement-label>
<attribute-help-text [attribute]="descriptor.name" [attributeScope]="'WorkPackage'"></attribute-help-text>
</div>
<div
*ngIf="!descriptor.multiple && descriptor.field"
class="attributes-key-value--value-container"
>
<op-editable-attribute-field
[ngClass]="{'wp-edit-formattable-field': descriptor.field!.isFormattable }"
[resource]="workPackage"
[isDropTarget]="descriptor.field!.isFormattable"
[fieldName]="fieldName(descriptor.name)"
></op-editable-attribute-field>
</div>
</ng-template>
</div>

@ -93,13 +93,14 @@
</div>
</div>
<div *ngFor="let group of groupedFields; trackBy:trackByName"
[hidden]="shouldHideGroup(group)"
[attr.data-group-name]="group.name"
[ngClass]="'__overflowing_' + group.id"
[attr.data-overflowing-identifier]="'.__overflowing_' + group.id"
class="attributes-group __overflowing_element_container">
<div
*ngFor="let group of groupedFields; trackBy:trackByName"
[hidden]="shouldHideGroup(group)"
[attr.data-group-name]="group.name"
[ngClass]="'__overflowing_' + group.id"
[attr.data-overflowing-identifier]="'.__overflowing_' + group.id"
class="attributes-group __overflowing_element_container"
>
<ng-container wp-isolated-query-space *ngIf="group.isolated">
<ndc-dynamic [ndcDynamicComponent]="attributeGroupComponent(group)"
[ndcDynamicInputs]="{ workPackage: workPackage,

@ -194,6 +194,7 @@ export class EditableAttributeFieldComponent extends UntilDestroyedMixin impleme
public handleUserActivate(evt:MouseEvent|KeyboardEvent|null):boolean {
let positionOffset = 0;
// This can be both a direct click as well as a "click" via keyboard, e.g. the <Enter> key.
if (evt?.type === 'click') {
// Get the position where the user clicked.
positionOffset = getPosition(evt);

@ -79,21 +79,6 @@
textarea
resize: vertical
// Implement two column layout for WP full screen view
&_with-columns
@media screen and (min-width: 92rem), print
.-columns-2
@include two-column-layout
@supports (column-span: all)
// Remove the outline on focus since that breaks the column in chrome
// Chrome bug https://bugs.chromium.org/p/chromium/issues/detail?id=565116
body
.attributes-key-value--value-container
*:focus
outline: 1px solid $gray
.detail-panel-description
margin: 0
line-height: 18px

Loading…
Cancel
Save