Browse Source

Autofix modals. (#788)

* Autofix modals.

* Fix build.
pull/793/head
Sebastian Stehle 5 years ago
committed by GitHub
parent
commit
4135a48ca0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      frontend/app/features/apps/pages/app.component.html
  2. 2
      frontend/app/features/assets/pages/assets-page.component.html
  3. 4
      frontend/app/features/content/pages/content/content-history-page.component.html
  4. 8
      frontend/app/features/content/pages/content/content-page.component.html
  5. 2
      frontend/app/features/content/pages/content/editor/field-copy-button.component.html
  6. 6
      frontend/app/features/content/pages/contents/contents-page.component.html
  7. 3
      frontend/app/features/content/pages/contents/custom-view-editor.component.scss
  8. 2
      frontend/app/features/content/shared/forms/array-editor.component.html
  9. 2
      frontend/app/features/content/shared/forms/component.component.html
  10. 2
      frontend/app/features/content/shared/list/content.component.html
  11. 2
      frontend/app/features/content/shared/preview-button.component.html
  12. 2
      frontend/app/features/dashboard/pages/dashboard-config.component.html
  13. 6
      frontend/app/features/rules/pages/rule/rule-page.component.html
  14. 2
      frontend/app/features/rules/pages/rules/rule.component.html
  15. 4
      frontend/app/features/rules/pages/rules/rules-page.component.html
  16. 2
      frontend/app/features/schemas/pages/schema/fields/field.component.html
  17. 2
      frontend/app/features/schemas/pages/schema/fields/types/string-validation.component.html
  18. 4
      frontend/app/features/schemas/pages/schema/schema-page.component.html
  19. 2
      frontend/app/features/settings/pages/asset-scripts/asset-scripts-page.component.html
  20. 2
      frontend/app/features/settings/pages/backups/backups-page.component.html
  21. 4
      frontend/app/features/settings/pages/clients/clients-page.component.html
  22. 4
      frontend/app/features/settings/pages/contributors/contributors-page.component.html
  23. 4
      frontend/app/features/settings/pages/languages/languages-page.component.html
  24. 2
      frontend/app/features/settings/pages/plans/plans-page.component.html
  25. 4
      frontend/app/features/settings/pages/roles/roles-page.component.html
  26. 2
      frontend/app/features/settings/pages/workflows/workflows-page.component.html
  27. 2
      frontend/app/framework/angular/forms/editors/autocomplete.component.html
  28. 3
      frontend/app/framework/angular/forms/editors/autocomplete.component.ts
  29. 2
      frontend/app/framework/angular/forms/editors/dropdown.component.html
  30. 2
      frontend/app/framework/angular/forms/editors/tag-editor.component.html
  31. 2
      frontend/app/framework/angular/language-selector.component.html
  32. 44
      frontend/app/framework/angular/modals/modal-placement.directive.ts
  33. 3
      frontend/app/framework/angular/modals/onboarding-tooltip.component.ts
  34. 6
      frontend/app/framework/angular/modals/tooltip.directive.ts
  35. 3
      frontend/app/framework/services/dialog.service.ts
  36. 18
      frontend/app/framework/utils/modal-positioner.spec.ts
  37. 85
      frontend/app/framework/utils/modal-positioner.ts
  38. 2
      frontend/app/shared/components/assets/asset-folder-dropdown.component.html
  39. 2
      frontend/app/shared/components/assets/asset-folder.component.html
  40. 2
      frontend/app/shell/pages/internal/apps-menu.component.html
  41. 2
      frontend/app/shell/pages/internal/profile-menu.component.html

2
frontend/app/features/apps/pages/app.component.html

@ -29,7 +29,7 @@
</button>
<ng-container *sqxModal="dropdown;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" [scrollY]="true" @fade>
<a class="dropdown-item dropdown-item-delete"
(sqxConfirmClick)="leave.emit(app)"
confirmTitle="i18n:apps.leaveConfirmTitle"

2
frontend/app/features/assets/pages/assets-page.component.html

@ -66,7 +66,7 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link" routerLink="filters" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.filters" titlePosition="left">
<a class="panel-link" routerLink="filters" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.filters" titlePosition="left-center">
<i class="icon-filter"></i>
</a>
</div>

4
frontend/app/features/content/pages/content/content-history-page.component.html

@ -32,7 +32,7 @@
</button>
<ng-container *sqxModal="dropdownNew;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" [scrollY]="true" @fade>
<ng-container *ngIf="content.statusUpdates.length > 0">
<a class="dropdown-item" *ngFor="let info of content.statusUpdates" (click)="changeStatus(info.status)">
{{ 'common.statusChangeTo' | sqxTranslate }} <i class="icon-circle icon-sm" [style.color]="info.color"></i> {{info.status}}
@ -77,7 +77,7 @@
</button>
<ng-container *sqxModal="dropdown;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" [scrollY]="true" @fade>
<ng-container *ngIf="content.statusUpdates.length > 0">
<a class="dropdown-item" *ngFor="let info of content.statusUpdates" (click)="changeStatus(info.status)">
{{ 'common.statusChangeTo' | sqxTranslate }}

8
frontend/app/features/content/pages/content/content-page.component.html

@ -65,7 +65,7 @@
</button>
<ng-container *sqxModal="dropdown;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" [scrollY]="true" @fade>
<a class="dropdown-item dropdown-item-delete"
(sqxConfirmClick)="delete()"
confirmTitle="i18n:contents.deleteConfirmTitle"
@ -157,15 +157,15 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link" routerLink="history" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.workflow" titlePosition="left" #linkHistory>
<a class="panel-link" routerLink="history" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.workflow" titlePosition="left-center" #linkHistory>
<i class="icon-time"></i>
</a>
<a class="panel-link" routerLink="comments" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.comments" titlePosition="left">
<a class="panel-link" routerLink="comments" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.comments" titlePosition="left-center">
<i class="icon-comments"></i>
</a>
<a class="panel-link" routerLink="sidebar" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.sidebar" titlePosition="left" *ngIf="schema.properties.contentSidebarUrl">
<a class="panel-link" routerLink="sidebar" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.sidebar" titlePosition="left-center" *ngIf="schema.properties.contentSidebarUrl">
<i class="icon-plugin"></i>
</a>

2
frontend/app/features/content/pages/content/editor/field-copy-button.component.html

@ -4,7 +4,7 @@
</button>
<ng-container *sqxModal="dropdown">
<div class="dropdown-menu" [sqxAnchoredTo]="button" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="button" [scrollY]="true" @fade>
<div class="section d-flex justify-content-end">
<button type="button" class="btn btn-primary" (click)="copy()" tabindex="-1">
{{ 'common.copy' | sqxTranslate }}

6
frontend/app/features/content/pages/contents/contents-page.component.html

@ -62,7 +62,7 @@
</button>
<ng-container *sqxModal="tableViewModal">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonSettings" @fade position="bottom-right">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonSettings" [scrollY]="true" @fade position="bottom-right">
<sqx-custom-view-editor
[allFields]="tableView.allFields"
(fieldNamesChange)="tableView.updateFields($event)"
@ -130,11 +130,11 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link" routerLink="filters" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.filters" titlePosition="left">
<a class="panel-link" routerLink="filters" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.filters" titlePosition="left-center">
<i class="icon-filter"></i>
</a>
<a class="panel-link" routerLink="sidebar" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.sidebar" titlePosition="left" *ngIf="schema.properties.contentsSidebarUrl">
<a class="panel-link" routerLink="sidebar" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.sidebar" titlePosition="left-center" *ngIf="schema.properties.contentsSidebarUrl">
<i class="icon-plugin"></i>
</a>
</div>

3
frontend/app/features/content/pages/contents/custom-view-editor.component.scss

@ -1,7 +1,4 @@
.container {
max-height: 400px;
overflow-x: hidden;
overflow-y: auto;
padding: .5rem 1rem;
}

2
frontend/app/features/content/shared/forms/array-editor.component.html

@ -72,7 +72,7 @@
</button>
<ng-container *sqxModal="schemasDropdown;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonSelect" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="buttonSelect" [scrollY]="true" @fade>
<a class="dropdown-item" *ngFor="let schema of schemasList" (click)="addComponent(schema)">
{{schema.displayName}}
</a>

2
frontend/app/features/content/shared/forms/component.component.html

@ -23,7 +23,7 @@
</button>
<ng-container *sqxModal="schemasDropdown;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonSelect" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="buttonSelect" [scrollY]="true" @fade>
<a class="dropdown-item" *ngFor="let schema of schemasList" (click)="setSchema(schema)">
{{schema.displayName}}
</a>

2
frontend/app/features/content/shared/list/content.component.html

@ -27,7 +27,7 @@
</button>
<ng-container *sqxModal="dropdown;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" position="bottom-left" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" [scrollY]="true" position="bottom-left" @fade>
<a class="dropdown-item" *ngFor="let info of content.statusUpdates" (click)="statusChange.emit(info.status)">
{{ 'common.statusChangeTo' | sqxTranslate }}

2
frontend/app/features/content/shared/preview-button.component.html

@ -10,7 +10,7 @@
<button type="button" class="btn btn-secondary dropdown-toggle" (click)="dropdown.toggle()"></button>
<ng-container *sqxModal="dropdown;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonGroup" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="buttonGroup" [scrollY]="true" @fade>
<a *ngFor="let name of snapshot.previewNamesMore" class="dropdown-item" (click)="follow(name)">{{name}}</a>
</div>
</ng-container>

2
frontend/app/features/dashboard/pages/dashboard-config.component.html

@ -4,7 +4,7 @@
</button>
<ng-container *sqxModal="dropdownModal">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonSettings" @fade position="bottom-right">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonSettings" [scrollY]="true" @fade position="bottom-right">
<div class="dropdown-item" *ngFor="let item of configOptions">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="field_{{item.type}}" [ngModel]="isSelected(item)" (ngModelChange)="addOrRemove(item)">

6
frontend/app/features/rules/pages/rule/rule-page.component.html

@ -153,16 +153,16 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<ng-container *ngIf="rule && (rulesState.canReadEvents | async)">
<a class="panel-link panel-link-gray" routerLink="events" [queryParams]="{ ruleId: rule.id }" routerLinkActive="active" title="i18n:common.history" titlePosition="left">
<a class="panel-link panel-link-gray" routerLink="events" [queryParams]="{ ruleId: rule.id }" routerLinkActive="active" title="i18n:common.history" titlePosition="left-center">
<i class="icon-time"></i>
</a>
<a class="panel-link panel-link-gray" routerLink="simulator" [queryParams]="{ ruleId: rule.id }" routerLinkActive="active" title="i18n:rules.simulator" titlePosition="left">
<a class="panel-link panel-link-gray" routerLink="simulator" [queryParams]="{ ruleId: rule.id }" routerLinkActive="active" title="i18n:rules.simulator" titlePosition="left-center">
<i class="icon-play-line"></i>
</a>
</ng-container>
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left" #helpLink>
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left-center" #helpLink>
<i class="icon-help2"></i>
</a>

2
frontend/app/features/rules/pages/rules/rule.component.html

@ -16,7 +16,7 @@
</button>
<ng-container *sqxModal="dropdown;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" position="bottom-right" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" [scrollY]="true" position="bottom-right" @fade>
<a class="dropdown-item" *ngIf="rule.canUpdate" [routerLink]="rule.id">
{{ 'common.edit' | sqxTranslate }}
</a>

4
frontend/app/features/rules/pages/rules/rules-page.component.html

@ -43,11 +43,11 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link panel-link-gray" routerLink="events" routerLinkActive="active" title="i18n:common.history" titlePosition="left" *ngIf="rulesState.canReadEvents | async">
<a class="panel-link panel-link-gray" routerLink="events" routerLinkActive="active" title="i18n:common.history" titlePosition="left-center" *ngIf="rulesState.canReadEvents | async">
<i class="icon-time"></i>
</a>
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left" #helpLink>
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left-center" #helpLink>
<i class="icon-help2"></i>
</a>

2
frontend/app/features/schemas/pages/schema/fields/field.component.html

@ -46,7 +46,7 @@
</button>
<ng-container *sqxModal="dropdown;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" [scrollY]="true" @fade>
<ng-container *ngIf="field.properties.isContentField">
<a class="dropdown-item" (click)="enableField()" *ngIf="field.canEnable">
{{ 'schemas.field.enable' | sqxTranslate }}

2
frontend/app/features/schemas/pages/schema/fields/types/string-validation.component.html

@ -36,7 +36,7 @@
<ng-container *ngIf="settings.patterns.length > 0 && (showPatternSuggestions | async)">
<ng-container *sqxModal="patternsModal">
<div class="control-dropdown" [sqxAnchoredTo]="inputPattern" position="bottom-left" @fade>
<div class="control-dropdown" [sqxAnchoredTo]="inputPattern" [scrollY]="true" position="bottom-left" @fade>
<h4>{{ 'schemas.fieldTypes.string.suggestions' | sqxTranslate }}</h4>
<div *ngFor="let pattern of settings.patterns" class="control-dropdown-item control-dropdown-item-selectable" (mousedown)="setPattern(pattern)">

4
frontend/app/features/schemas/pages/schema/schema-page.component.html

@ -46,7 +46,7 @@
</button>
<ng-container *sqxModal="editOptionsDropdown;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" [scrollY]="true" @fade>
<ng-container *ngIf="schemasState.canCreate">
<div class="dropdown-divider"></div>
@ -118,7 +118,7 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left">
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left-center">
<i class="icon-help"></i>
</a>
</div>

2
frontend/app/features/settings/pages/asset-scripts/asset-scripts-page.component.html

@ -37,7 +37,7 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left">
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left-center">
<i class="icon-help2"></i>
</a>
</div>

2
frontend/app/features/settings/pages/backups/backups-page.component.html

@ -34,7 +34,7 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left">
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left-center">
<i class="icon-help2"></i>
</a>
</div>

4
frontend/app/features/settings/pages/clients/clients-page.component.html

@ -28,11 +28,11 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link" routerLink="history" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.history" titlePosition="left">
<a class="panel-link" routerLink="history" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.history" titlePosition="left-center">
<i class="icon-time"></i>
</a>
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left">
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left-center">
<i class="icon-help2"></i>
</a>
</div>

4
frontend/app/features/settings/pages/contributors/contributors-page.component.html

@ -62,11 +62,11 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link" routerLink="history" routerLinkActive="active" queryParamsHandling="preserve" queryParamsHandling="preserve" title="i18n:common.history" titlePosition="left">
<a class="panel-link" routerLink="history" routerLinkActive="active" queryParamsHandling="preserve" queryParamsHandling="preserve" title="i18n:common.history" titlePosition="left-center">
<i class="icon-time"></i>
</a>
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left">
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left-center">
<i class="icon-help2"></i>
</a>
</div>

4
frontend/app/features/settings/pages/languages/languages-page.component.html

@ -27,11 +27,11 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link" routerLink="history" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.history" titlePosition="left">
<a class="panel-link" routerLink="history" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.history" titlePosition="left-center">
<i class="icon-time"></i>
</a>
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left">
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left-center">
<i class="icon-help2"></i>
</a>
</div>

2
frontend/app/features/settings/pages/plans/plans-page.component.html

@ -37,7 +37,7 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link" routerLink="history" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.history" titlePosition="left">
<a class="panel-link" routerLink="history" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.history" titlePosition="left-center">
<i class="icon-time"></i>
</a>
</div>

4
frontend/app/features/settings/pages/roles/roles-page.component.html

@ -41,11 +41,11 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link" routerLink="history" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.history" titlePosition="left">
<a class="panel-link" routerLink="history" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.history" titlePosition="left-center">
<i class="icon-time"></i>
</a>
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left">
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left-center">
<i class="icon-help2"></i>
</a>
</div>

2
frontend/app/features/settings/pages/workflows/workflows-page.component.html

@ -38,7 +38,7 @@
<ng-container sidebarMenu>
<div class="panel-nav">
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left">
<a class="panel-link" routerLink="help" routerLinkActive="active" queryParamsHandling="preserve" title="i18n:common.help" titlePosition="left-center">
<i class="icon-help2"></i>
</a>
</div>

2
frontend/app/framework/angular/forms/editors/autocomplete.component.html

@ -16,7 +16,7 @@
</div>
<ng-container *sqxModal="snapshot.suggestedItems.length > 0">
<div class="control-dropdown" [sqxAnchoredTo]="input" [style.width]="dropdownWidth" [position]="dropdownPosition" #container @fade>
<div class="control-dropdown" [sqxAnchoredTo]="input" [scrollY]="true" [style.width]="dropdownWidth" [position]="dropdownPosition" #container @fade>
<div *ngFor="let item of snapshot.suggestedItems; let i = index" class="control-dropdown-item control-dropdown-item-selectable"
[class.active]="i === snapshot.suggestedIndex"
(mousedown)="selectItem(item)"

3
frontend/app/framework/angular/forms/editors/autocomplete.component.ts

@ -8,6 +8,7 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ElementRef, forwardRef, Input, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { fadeAnimation, Keys, StatefulControlComponent, Types } from '@app/framework/internal';
import { RelativePosition } from '@app/shared';
import { Observable, of } from 'rxjs';
import { catchError, debounceTime, distinctUntilChanged, finalize, map, switchMap, tap } from 'rxjs/operators';
@ -75,7 +76,7 @@ export class AutocompleteComponent extends StatefulControlComponent<State, Reado
public debounceTime = 300;
@Input()
public dropdownPosition = 'bottom-left';
public dropdownPosition: RelativePosition = 'bottom-left';
@Input()
public dropdownWidth = '18rem';

2
frontend/app/framework/angular/forms/editors/dropdown.component.html

@ -15,7 +15,7 @@
<div class="items-container">
<ng-container *sqxModal="dropdown">
<div class="control-dropdown" [sqxAnchoredTo]="input" position="bottom-left">
<div class="control-dropdown" [sqxAnchoredTo]="input" [scrollY]="true" position="bottom-left">
<div *ngIf="canSearch" class="search-form">
<input class="form-control search" [formControl]="queryInput" placeholder="{{ 'contributors.search' | sqxTranslate }}" (keydown)="onKeyDown($event)" sqxFocusOnInit>
</div>

2
frontend/app/framework/angular/forms/editors/tag-editor.component.html

@ -29,7 +29,7 @@
</div>
<ng-container *sqxModal="snapshot.suggestedItems.length > 0">
<div class="control-dropdown" [sqxAnchoredTo]="form" position="bottom-left" #container @fade>
<div class="control-dropdown" [sqxAnchoredTo]="form" [scrollY]="true" position="bottom-left" #container @fade>
<div *ngFor="let item of snapshot.suggestedItems; let i = index" class="control-dropdown-item control-dropdown-item-selectable"
[class.active]="i === snapshot.suggestedIndex"
[class.separated]="separated"

2
frontend/app/framework/angular/language-selector.component.html

@ -10,7 +10,7 @@
</button>
<ng-container *sqxModal="dropdown;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="button" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="button" [scrollY]="true" @fade>
<table>
<tbody>
<tr class="dropdown-item" *ngFor="let supported of languages; trackBy: trackByLanguage" [class.active]="supported === language" (click)="selectLanguage(supported)">

44
frontend/app/framework/angular/modals/modal-placement.directive.ts

@ -7,6 +7,7 @@
import { AfterViewInit, Directive, ElementRef, Input, OnDestroy, Renderer2 } from '@angular/core';
import { positionModal, ResourceOwner } from '@app/framework/internal';
import { RelativePosition } from '@app/shared';
import { timer } from 'rxjs';
@Directive({
@ -33,14 +34,23 @@ export class ModalPlacementDirective extends ResourceOwner implements AfterViewI
public offset = 2;
@Input()
public position = 'bottom-right';
public position: RelativePosition | 'full' = 'bottom-right';
@Input()
public scrollX = false;
@Input()
public scrollY = false;
@Input()
public scrollMargin = 10;
@Input()
public update = true;
constructor(
private readonly renderer: Renderer2,
private readonly element: ElementRef<Element>,
private readonly element: ElementRef<HTMLElement>,
) {
super();
}
@ -103,13 +113,37 @@ export class ModalPlacementDirective extends ResourceOwner implements AfterViewI
this.renderer.setStyle(modalRef, 'width', `${w}px`);
this.renderer.setStyle(modalRef, 'height', `${h}px`);
} else {
const viewH = document.documentElement!.clientHeight;
const viewW = document.documentElement!.clientWidth;
if (this.scrollX) {
modalRect.width = modalRef.scrollWidth;
}
if (this.scrollY) {
modalRect.height = modalRef.scrollHeight;
}
const viewportHeight = document.documentElement!.clientHeight;
const viewportWidth = document.documentElement!.clientWidth;
const position = positionModal(targetRect, modalRect, this.position, this.offset, this.update, viewW, viewH);
const position = positionModal(targetRect, modalRect, this.position, this.offset, this.update, viewportWidth, viewportHeight);
x = position.x;
y = position.y;
if (this.scrollX) {
const maxWidth = position.xMax > 0 ? `${position.xMax - 10}px` : 'none';
this.renderer.setStyle(modalRef, 'overflow-x', 'auto');
this.renderer.setStyle(modalRef, 'max-width', maxWidth);
this.renderer.setStyle(modalRef, 'min-width', 0);
}
if (this.scrollY) {
const maxHeight = position.yMax > 0 ? `${position.yMax - 10}px` : 'none';
this.renderer.setStyle(modalRef, 'overflow-y', 'auto');
this.renderer.setStyle(modalRef, 'max-height', maxHeight);
this.renderer.setStyle(modalRef, 'min-height', 0);
}
}
this.renderer.setStyle(modalRef, 'top', `${y}px`);

3
frontend/app/framework/angular/modals/onboarding-tooltip.component.ts

@ -7,6 +7,7 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { DialogModel, fadeAnimation, OnboardingService, StatefulComponent, Types } from '@app/framework/internal';
import { RelativePosition } from '@app/shared';
import { timer } from 'rxjs';
@Component({
@ -29,7 +30,7 @@ export class OnboardingTooltipComponent extends StatefulComponent implements OnD
public after = 1000;
@Input()
public position = 'left';
public position: RelativePosition = 'left-center';
public tooltipModal = new DialogModel();

6
frontend/app/framework/angular/modals/tooltip.directive.ts

@ -6,7 +6,7 @@
*/
import { Directive, ElementRef, HostListener, Input, OnDestroy, Renderer2 } from '@angular/core';
import { DialogService, Tooltip } from '@app/framework/internal';
import { DialogService, RelativePosition, Tooltip } from '@app/framework/internal';
@Directive({
selector: '[title]:not(sqx-layout),[shortcut]',
@ -17,7 +17,7 @@ export class TooltipDirective implements OnDestroy {
private shortcutTimer: any;
@Input()
public shortcutPosition = 'bottom-left';
public shortcutPosition: RelativePosition = 'bottom-left';
@Input()
public shortcut?: string | undefined;
@ -26,7 +26,7 @@ export class TooltipDirective implements OnDestroy {
public shortcutDelay = 2000;
@Input()
public titlePosition = 'top-right';
public titlePosition: RelativePosition = 'top-right';
@Input()
public titleDelay = 1000;

3
frontend/app/framework/services/dialog.service.ts

@ -7,6 +7,7 @@
import { Injectable } from '@angular/core';
import { Observable, ReplaySubject, Subject, throwError } from 'rxjs';
import { RelativePosition } from './../utils/modal-positioner';
import { ErrorDto } from './../utils/error';
import { Types } from './../utils/types';
import { LocalStoreService } from './local-store.service';
@ -60,7 +61,7 @@ export class Tooltip {
constructor(
public readonly target: any,
public readonly text: string | null | undefined,
public readonly position: string,
public readonly position: RelativePosition,
public readonly multiple?: boolean,
public readonly shortcut?: string,
) {

18
frontend/app/framework/utils/modal-positioner.spec.ts

@ -22,25 +22,25 @@ describe('position', () => {
const targetRect = buildRect(200, 200, 100, 100);
const tests = [
{ position: 'top', x: 235, y: 160 },
{ position: 'top-left', x: 200, y: 160 },
{ position: 'top-right', x: 270, y: 160 },
{ position: 'bottom', x: 235, y: 310 },
{ position: 'bottom-center', x: 235, y: 310 },
{ position: 'bottom-left', x: 200, y: 310 },
{ position: 'bottom-right', x: 270, y: 310 },
{ position: 'left', x: 160, y: 235 },
{ position: 'left-top', x: 160, y: 200 },
{ position: 'left-bottom', x: 160, y: 270 },
{ position: 'right', x: 310, y: 235 },
{ position: 'right-top', x: 310, y: 200 },
{ position: 'left-center', x: 160, y: 235 },
{ position: 'left-top', x: 160, y: 200 },
{ position: 'right-bottom', x: 310, y: 270 },
{ position: 'right-center', x: 310, y: 235 },
{ position: 'right-top', x: 310, y: 200 },
{ position: 'top-center', x: 235, y: 160 },
{ position: 'top-left', x: 200, y: 160 },
{ position: 'top-right', x: 270, y: 160 },
];
tests.forEach(test => {
it(`should calculate modal position for ${test.position}`, () => {
const modalRect = buildRect(0, 0, 30, 30);
const result = positionModal(targetRect, modalRect, test.position, 10, false, 0, 0);
const result = positionModal(targetRect, modalRect, test.position as any, 10, false, 1000, 1000);
expect(result.x).toBe(test.x);
expect(result.y).toBe(test.y);

85
frontend/app/framework/utils/modal-positioner.ts

@ -5,23 +5,48 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
const POSITION_TOP_CENTER = 'top';
const POSITION_TOP_LEFT = 'top-left';
const POSITION_TOP_RIGHT = 'top-right';
const POSITION_BOTTOM_CENTER = 'bottom';
export type RelativePosition =
'bottom-center' |
'bottom-left' |
'bottom-right' |
'left-bottom' |
'left-center' |
'left-top' |
'right-bottom' |
'right-center' |
'right-top' |
'top-center' |
'top-left' |
'top-right';
const POSITION_BOTTOM_CENTER = 'bottom-center';
const POSITION_BOTTOM_LEFT = 'bottom-left';
const POSITION_BOTTOM_RIGHT = 'bottom-right';
const POSITION_LEFT_CENTER = 'left';
const POSITION_LEFT_TOP = 'left-top';
const POSITION_LEFT_BOTTOM = 'left-bottom';
const POSITION_RIGHT_CENTER = 'right';
const POSITION_RIGHT_TOP = 'right-top';
const POSITION_LEFT_CENTER = 'left-center';
const POSITION_LEFT_TOP = 'left-top';
const POSITION_RIGHT_BOTTOM = 'right-bottom';
const POSITION_RIGHT_CENTER = 'right-center';
const POSITION_RIGHT_TOP = 'right-top';
const POSITION_TOP_CENTER = 'top-center';
const POSITION_TOP_LEFT = 'top-left';
const POSITION_TOP_RIGHT = 'top-right';
export function positionModal(targetRect: DOMRect, modalRect: DOMRect, relativePosition: string, offset: number, fix: boolean, viewportWidth: number, viewportHeight: number): { x: number; y: number } {
export type PositionResult = {
x: number;
y: number;
xMax: number;
yMax: number;
};
export function positionModal(targetRect: DOMRect, modalRect: DOMRect, relativePosition: RelativePosition, offset: number, fix: boolean, clientWidth: number, clientHeight: number): PositionResult {
let y = 0;
let x = 0;
// Available space in x/y direction.
let xMax = 0;
let yMax = 0;
switch (relativePosition) {
case POSITION_LEFT_TOP:
case POSITION_RIGHT_TOP: {
@ -38,11 +63,18 @@ export function positionModal(targetRect: DOMRect, modalRect: DOMRect, relativeP
case POSITION_BOTTOM_RIGHT: {
y = targetRect.bottom + offset;
if (fix && y + modalRect.height > viewportHeight) {
yMax = clientHeight - y;
// Unset yMax if we have enough space.
if (modalRect.height <= yMax) {
yMax = 0;
} else if (fix) {
// Find a position at the other side of the rect (top).
const candidate = targetRect.top - modalRect.height - offset;
if (candidate > 0) {
y = candidate;
// Reset space to zero (full space), becuase we fix only if we have the space.
yMax = 0;
}
}
break;
@ -52,11 +84,18 @@ export function positionModal(targetRect: DOMRect, modalRect: DOMRect, relativeP
case POSITION_TOP_RIGHT: {
y = targetRect.top - modalRect.height - offset;
if (fix && y < 0) {
yMax = targetRect.top - offset;
// Unset yMax if we have enough space.
if (modalRect.height <= yMax) {
yMax = 0;
} else if (fix) {
// Find a position at the other side of the rect (bottom).
const candidate = targetRect.bottom + offset;
if (candidate + modalRect.height < viewportHeight) {
if (candidate + modalRect.height < clientHeight) {
y = candidate;
// Reset space to zero (full space), becuase we fix only if we have the space.
yMax = 0;
}
}
break;
@ -83,11 +122,18 @@ export function positionModal(targetRect: DOMRect, modalRect: DOMRect, relativeP
case POSITION_RIGHT_BOTTOM: {
x = targetRect.right + offset;
if (fix && x + modalRect.width > viewportWidth) {
xMax = clientWidth - x;
// Unset xMax if we have enough space.
if (modalRect.width <= xMax) {
xMax = 0;
} else if (fix) {
// Find a position at the other side of the rect (left).
const candidate = targetRect.left - modalRect.width - offset;
if (candidate > 0) {
x = candidate;
// Reset space to zero (full space), becuase we fix only if we have the space.
xMax = 0;
}
}
break;
@ -97,11 +143,18 @@ export function positionModal(targetRect: DOMRect, modalRect: DOMRect, relativeP
case POSITION_LEFT_BOTTOM: {
x = targetRect.left - modalRect.width - offset;
if (fix && x < 0) {
xMax = targetRect.left - offset;
// Unset xMax if we have enough space.
if (modalRect.width <= xMax) {
xMax = 0;
} else if (fix) {
// Find a position at the other side of the rect (right).
const candidate = targetRect.right + offset;
if (candidate + modalRect.width < viewportWidth) {
if (candidate + modalRect.width < clientWidth) {
x = candidate;
// Reset space to zero (full space), becuase we fix only if we have the space.
xMax = 0;
}
}
break;
@ -112,5 +165,5 @@ export function positionModal(targetRect: DOMRect, modalRect: DOMRect, relativeP
break;
}
return { x, y };
return { x, y, xMax, yMax };
}

2
frontend/app/shared/components/assets/asset-folder-dropdown.component.html

@ -11,7 +11,7 @@
<div class="items-container">
<ng-container *sqxModal="dropdown">
<div class="control-dropdown" [sqxAnchoredTo]="input" position="bottom-left">
<div class="control-dropdown" [sqxAnchoredTo]="input" [scrollY]="true" position="bottom-left">
<sqx-asset-folder-dropdown-item
[appName]="appName"
[node]="root"

2
frontend/app/shared/components/assets/asset-folder.component.html

@ -14,7 +14,7 @@
</button>
<ng-container *sqxModal="dropdown;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="buttonOptions" [scrollY]="true" @fade>
<ng-container *ngIf="canUpdate">
<a class="dropdown-item" (click)="editDialog.show()">
{{ 'common.rename' | sqxTranslate }}

2
frontend/app/shell/pages/internal/apps-menu.component.html

@ -12,7 +12,7 @@
<ng-container *ngIf="appsState.apps | async; let apps">
<ng-container *sqxModal="appsMenu;closeAlways:true;onRoot:false">
<div class="dropdown-menu" [sqxAnchoredTo]="button" position="bottom-left" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="button" [scrollY]="true" position="bottom-left" @fade>
<a class="dropdown-item" routerLink="/app">
<div class="row g-0 align-items-center">
<div class="col">

2
frontend/app/shell/pages/internal/profile-menu.component.html

@ -9,7 +9,7 @@
</ul>
<ng-container *sqxModal="modalMenu;onRoot:false;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="button" [offset]="10" @fade>
<div class="dropdown-menu" [sqxAnchoredTo]="button" [scrollY]="true" [offset]="10" @fade>
<a class="dropdown-item dropdown-info" [sqxPopupLink]="snapshot.profileUrl">
<div>{{ 'profile.userEmail' | sqxTranslate }}</div>

Loading…
Cancel
Save