newportsite 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/newportsite-1.1.3.tgz +0 -0
- package/ng-package.json +7 -0
- package/obfuscate.js +70 -0
- package/package.json +15 -0
- package/src/lib/app.component.ts +47 -0
- package/src/lib/app.routing.ts +38 -0
- package/src/lib/auth/alert.component.html +5 -0
- package/src/lib/auth/alert.component.ts +24 -0
- package/src/lib/auth/auth.component.html +1 -0
- package/src/lib/auth/auth.component.ts +10 -0
- package/src/lib/auth/auth.routes.ts +16 -0
- package/src/lib/auth/index.ts +4 -0
- package/src/lib/auth/login.component.html +87 -0
- package/src/lib/auth/login.component.ts +158 -0
- package/src/lib/auth/models/index.ts +1 -0
- package/src/lib/auth/models/user.ts +25 -0
- package/src/lib/auth/register.component.html +157 -0
- package/src/lib/auth/register.component.ts +219 -0
- package/src/lib/auth/services/alert.service.ts +47 -0
- package/src/lib/auth/services/auth.service.ts +28 -0
- package/src/lib/auth/services/index.ts +3 -0
- package/src/lib/auth/services/user.service.spec.ts +112 -0
- package/src/lib/auth/services/user.service.ts +47 -0
- package/src/lib/common/card.component.html +72 -0
- package/src/lib/common/card.component.ts +102 -0
- package/src/lib/common/commands.component.html +8 -0
- package/src/lib/common/commands.component.ts +42 -0
- package/src/lib/common/context.component.html +9 -0
- package/src/lib/common/context.component.ts +38 -0
- package/src/lib/common/grid.component.html +20 -0
- package/src/lib/common/grid.component.ts +747 -0
- package/src/lib/common/index.ts +9 -0
- package/src/lib/common/loader.component.html +5 -0
- package/src/lib/common/loader.component.ts +27 -0
- package/src/lib/common/lookup.component.html +29 -0
- package/src/lib/common/lookup.component.ts +115 -0
- package/src/lib/common/messagebox.component.html +39 -0
- package/src/lib/common/messagebox.component.ts +74 -0
- package/src/lib/common/theme-toggle.component.ts +139 -0
- package/src/lib/config.ts +62 -0
- package/src/lib/containers/default-layout/default-layout.component.html +191 -0
- package/src/lib/containers/default-layout/default-layout.component.ts +158 -0
- package/src/lib/containers/default-layout/index.ts +1 -0
- package/src/lib/containers/index.ts +1 -0
- package/src/lib/directives/component.draggable.ts +80 -0
- package/src/lib/directives/index.ts +2 -0
- package/src/lib/directives/input.directive.spec.ts +158 -0
- package/src/lib/directives/input.directive.ts +210 -0
- package/src/lib/home/dashboard/dashboard.component.html +38 -0
- package/src/lib/home/dashboard/dashboard.component.ts +50 -0
- package/src/lib/home/dashboard/index.ts +1 -0
- package/src/lib/home/index.component.html +1 -0
- package/src/lib/home/index.component.ts +10 -0
- package/src/lib/home/index.routes.ts +29 -0
- package/src/lib/home/index.ts +1 -0
- package/src/lib/home/info/index.ts +1 -0
- package/src/lib/home/info/info.component.css +476 -0
- package/src/lib/home/info/info.component.html +174 -0
- package/src/lib/home/info/info.component.ts +287 -0
- package/src/lib/home/model/article.component.html +10 -0
- package/src/lib/home/model/article.component.ts +50 -0
- package/src/lib/home/model/barchart.component.html +8 -0
- package/src/lib/home/model/barchart.component.ts +59 -0
- package/src/lib/home/model/index.ts +7 -0
- package/src/lib/home/model/itemdetail.component.html +25 -0
- package/src/lib/home/model/itemdetail.component.ts +93 -0
- package/src/lib/home/model/itemtab.component.html +25 -0
- package/src/lib/home/model/itemtab.component.ts +105 -0
- package/src/lib/home/model/model.component.html +121 -0
- package/src/lib/home/model/model.component.ts +510 -0
- package/src/lib/home/model/modeltoolbar.component.html +111 -0
- package/src/lib/home/model/modeltoolbar.component.ts +157 -0
- package/src/lib/home/model/navigation.component.html +86 -0
- package/src/lib/home/model/navigation.component.ts +247 -0
- package/src/lib/home/model/services/index.ts +1 -0
- package/src/lib/home/model/services/model.service.spec.ts +423 -0
- package/src/lib/home/model/services/model.service.ts +319 -0
- package/src/lib/home/modelsearch/index.ts +1 -0
- package/src/lib/home/modelsearch/modelsearch.component.html +124 -0
- package/src/lib/home/modelsearch/modelsearch.component.ts +453 -0
- package/src/lib/interfaces/data.interface.ts +131 -0
- package/src/lib/interfaces/index.ts +2 -0
- package/src/lib/interfaces/item.interface.ts +438 -0
- package/src/lib/players/lookup/lookup.directive.ts +6 -0
- package/src/lib/players/lookup/lookup.item.component.ts +37 -0
- package/src/lib/players/lookup/lookup.item.ts +9 -0
- package/src/lib/players/lookup/lookup.player.component.ts +59 -0
- package/src/lib/players/lookup/lookup.selector.component.ts +41 -0
- package/src/lib/players/model/model.directive.ts +6 -0
- package/src/lib/players/model/model.item.component.spec.ts +311 -0
- package/src/lib/players/model/model.item.component.ts +3457 -0
- package/src/lib/players/model/model.item.ts +9 -0
- package/src/lib/players/model/model.player.component.ts +109 -0
- package/src/lib/players/model/model.selector.component.ts +59 -0
- package/src/lib/scheduler/scheduler.component.html +13 -0
- package/src/lib/scheduler/scheduler.component.scss +6 -0
- package/src/lib/scheduler/scheduler.component.ts +296 -0
- package/src/lib/scheduler/scheduler.routes.ts +15 -0
- package/src/lib/scheduler/schedulerdialog.component.html +72 -0
- package/src/lib/scheduler/schedulerdialog.component.ts +208 -0
- package/src/lib/scheduler/services/scheduler.service.ts +133 -0
- package/src/lib/services/auth-state.service.ts +129 -0
- package/src/lib/services/auth.interceptor.spec.ts +144 -0
- package/src/lib/services/auth.interceptor.ts +44 -0
- package/src/lib/services/cache.service.spec.ts +143 -0
- package/src/lib/services/cache.service.ts +71 -0
- package/src/lib/services/global-error-handler.spec.ts +39 -0
- package/src/lib/services/global-error-handler.ts +28 -0
- package/src/lib/services/global.service.spec.ts +801 -0
- package/src/lib/services/global.service.ts +724 -0
- package/src/lib/services/message.service.ts +556 -0
- package/src/lib/services/theme.service.ts +96 -0
- package/src/lib/template/authtemplate.component.html +6 -0
- package/src/lib/template/authtemplate.component.ts +13 -0
- package/src/lib/template/basetemplate.component.html +7 -0
- package/src/lib/template/basetemplate.component.ts +13 -0
- package/src/lib/template/index.ts +3 -0
- package/src/lib/template/modeltemplate.component.html +7 -0
- package/src/lib/template/modeltemplate.component.ts +21 -0
- package/src/lib/utils/piva.spec.ts +56 -0
- package/src/lib/utils/piva.ts +29 -0
- package/src/lib/validators/email.validator.spec.ts +57 -0
- package/src/lib/validators/email.validator.ts +17 -0
- package/src/lib/validators/equalPasswords.validator.spec.ts +54 -0
- package/src/lib/validators/equalPasswords.validator.ts +17 -0
- package/src/lib/validators/index.ts +2 -0
- package/src/lib/version.ts +1 -0
- package/src/public-api.ts +64 -0
- package/src/typings.d.ts +2 -0
- package/tsconfig.lib.json +18 -0
- package/tsconfig.lib.prod.json +9 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<!-- model.component -->
|
|
2
|
+
<modeltemplate>
|
|
3
|
+
<div class="scale-outer-wrapper" #outerWrapper>
|
|
4
|
+
<div
|
|
5
|
+
class="fill scale-container"
|
|
6
|
+
#mainContainer
|
|
7
|
+
[style.transform]="scaleTransform">
|
|
8
|
+
<div class="d-flex h-100 model-split-layout">
|
|
9
|
+
<div
|
|
10
|
+
class="model-split-nav overflow-hidden"
|
|
11
|
+
[style.width.%]="navAreaSize">
|
|
12
|
+
<navigation
|
|
13
|
+
[model]="currentModel"
|
|
14
|
+
[collapsed]="navCollapsed"
|
|
15
|
+
(modelChanged)="modelChanged($event)"
|
|
16
|
+
(hideNavigation)="navigationState($event)"
|
|
17
|
+
(collapsedChanged)="navigationCollapsed($event)">
|
|
18
|
+
</navigation>
|
|
19
|
+
</div>
|
|
20
|
+
<div
|
|
21
|
+
class="d-flex flex-column model-split-content overflow-hidden"
|
|
22
|
+
[style.width.%]="contentAreaSize">
|
|
23
|
+
<div class="model-header">
|
|
24
|
+
<div class="model-title truncate" [title]="modelTitle">
|
|
25
|
+
{{ msg?.getItemInfo(currentModel, 'title') }}
|
|
26
|
+
{{ gsv?.getExtendedDescription() }}
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<div>
|
|
30
|
+
<modeltoolbar
|
|
31
|
+
[hidden]="hide"
|
|
32
|
+
[commands]="commands"
|
|
33
|
+
(commandRaised)="commandRaised($event)"
|
|
34
|
+
(viewChanged)="viewChanged($event)"
|
|
35
|
+
[disabled]="showlookup()"></modeltoolbar>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="model-breadcrumb">
|
|
38
|
+
@for (
|
|
39
|
+
breadCrumb of breadCrumbs;
|
|
40
|
+
track breadCrumb;
|
|
41
|
+
let isFirst = $first;
|
|
42
|
+
let isLast = $last
|
|
43
|
+
) {
|
|
44
|
+
<span class="bc-item" [class.bc-last]="isLast">
|
|
45
|
+
@if (!isFirst) {
|
|
46
|
+
<span class="bc-sep"></span>
|
|
47
|
+
}
|
|
48
|
+
<span class="bc-label">{{ breadCrumb }}</span>
|
|
49
|
+
</span>
|
|
50
|
+
}
|
|
51
|
+
</div>
|
|
52
|
+
<div class="d-flex" style="gap: 2px">
|
|
53
|
+
<itemtab
|
|
54
|
+
[model]="currentModel"
|
|
55
|
+
[hidden]="viewList"
|
|
56
|
+
(modelChanged)="modelChanged($event)"
|
|
57
|
+
[insertMode]="insertMode"
|
|
58
|
+
[disabled]="showlookup()"></itemtab>
|
|
59
|
+
<itemdetail
|
|
60
|
+
[model]="currentModel"
|
|
61
|
+
[hidden]="viewList"
|
|
62
|
+
(modelChanged)="modelChanged($event)"
|
|
63
|
+
[insertMode]="insertMode"
|
|
64
|
+
[disabled]="showlookup()"></itemdetail>
|
|
65
|
+
</div>
|
|
66
|
+
<div
|
|
67
|
+
id="container"
|
|
68
|
+
#contentContainer
|
|
69
|
+
class="flex-grow-1 overflow-auto"
|
|
70
|
+
style="min-height: 0">
|
|
71
|
+
<article
|
|
72
|
+
[model]="currentModel"
|
|
73
|
+
[command]="currentCommand"
|
|
74
|
+
(viewChanged)="viewChanged($event)"
|
|
75
|
+
(commandsChanged)="commandsChanged($event)"
|
|
76
|
+
[viewList]="viewList"
|
|
77
|
+
[lookupValue]="lookupValue()"
|
|
78
|
+
[dialogValue]="dialogValue()"
|
|
79
|
+
[scale]="scale"></article>
|
|
80
|
+
<grid
|
|
81
|
+
[hidden]="gridHidden"
|
|
82
|
+
[style.opacity]="gridOpacity"
|
|
83
|
+
[model]="currentModel"
|
|
84
|
+
(viewChanged)="viewChanged($event)"
|
|
85
|
+
[viewList]="viewList"
|
|
86
|
+
[refreshGrid]="refreshGrid"
|
|
87
|
+
[print]="print"></grid>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
@if (showlookup()) {
|
|
92
|
+
<lookup
|
|
93
|
+
[show]="showlookup()"
|
|
94
|
+
[(text)]="textlookup"
|
|
95
|
+
[(title)]="titlelookup"
|
|
96
|
+
(lookupResult)="lookupResult($event)"
|
|
97
|
+
[(width)]="lookupWidth"
|
|
98
|
+
[(height)]="lookupHeight"
|
|
99
|
+
[(top)]="lookupTop"
|
|
100
|
+
[(left)]="lookupLeft"
|
|
101
|
+
[(lookup)]="lookup"
|
|
102
|
+
[(filter)]="lookupfilter">
|
|
103
|
+
</lookup>
|
|
104
|
+
}
|
|
105
|
+
@if (showdialog()) {
|
|
106
|
+
<messagebox
|
|
107
|
+
[show]="showdialog()"
|
|
108
|
+
[(text)]="textdialog"
|
|
109
|
+
[(title)]="titledialog"
|
|
110
|
+
(messageResult)="dialogResult($event)"
|
|
111
|
+
[(showconfirm)]="showconfirm"
|
|
112
|
+
[(width)]="dialogWidth"
|
|
113
|
+
[(height)]="dialogHeight"
|
|
114
|
+
[(top)]="dialogTop"
|
|
115
|
+
[(left)]="dialogLeft">
|
|
116
|
+
</messagebox>
|
|
117
|
+
}
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</modeltemplate>
|
|
121
|
+
<!-- fine model.component-->
|
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Component,
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
AfterViewInit,
|
|
5
|
+
viewChild,
|
|
6
|
+
ElementRef,
|
|
7
|
+
signal,
|
|
8
|
+
HostListener,
|
|
9
|
+
DestroyRef,
|
|
10
|
+
inject,
|
|
11
|
+
AfterViewChecked,
|
|
12
|
+
} from '@angular/core';
|
|
13
|
+
|
|
14
|
+
import { GlobalService } from '../../services/global.service';
|
|
15
|
+
|
|
16
|
+
import { AppMessageService } from '../../services/message.service';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
ItemCommandInterface,
|
|
20
|
+
ItemInterface,
|
|
21
|
+
ViewListInterface,
|
|
22
|
+
LookupFieldInterface,
|
|
23
|
+
DialogFieldInterface,
|
|
24
|
+
} from '../../interfaces/index';
|
|
25
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
26
|
+
import { ModelTemplateComponent } from '../../template/modeltemplate.component';
|
|
27
|
+
import { NavigationComponent } from './navigation.component';
|
|
28
|
+
import { ModelToolbarComponent } from './modeltoolbar.component';
|
|
29
|
+
import { ItemTabComponent } from './itemtab.component';
|
|
30
|
+
import { ItemDetailComponent } from './itemdetail.component';
|
|
31
|
+
import { ArticleComponent } from './article.component';
|
|
32
|
+
import { GridComponent } from '../../common/grid.component';
|
|
33
|
+
import { LookupComponent } from '../../common/lookup.component';
|
|
34
|
+
import { MessageBoxComponent } from '../../common/messagebox.component';
|
|
35
|
+
|
|
36
|
+
@Component({
|
|
37
|
+
selector: 'app-model',
|
|
38
|
+
templateUrl: 'model.component.html',
|
|
39
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
40
|
+
imports: [
|
|
41
|
+
ModelTemplateComponent,
|
|
42
|
+
NavigationComponent,
|
|
43
|
+
ModelToolbarComponent,
|
|
44
|
+
ItemTabComponent,
|
|
45
|
+
ItemDetailComponent,
|
|
46
|
+
ArticleComponent,
|
|
47
|
+
GridComponent,
|
|
48
|
+
LookupComponent,
|
|
49
|
+
MessageBoxComponent,
|
|
50
|
+
],
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
export class ModelComponent implements AfterViewInit, AfterViewChecked {
|
|
54
|
+
|
|
55
|
+
gsv = inject(GlobalService);
|
|
56
|
+
msg = inject(AppMessageService);
|
|
57
|
+
|
|
58
|
+
public commands: ItemCommandInterface[] = [];
|
|
59
|
+
public currentModel!: ItemInterface;
|
|
60
|
+
public previousModel!: ItemInterface;
|
|
61
|
+
public viewList = true;
|
|
62
|
+
public currentCommand!: ItemCommandInterface;
|
|
63
|
+
public insertMode = false;
|
|
64
|
+
public refreshGrid = false;
|
|
65
|
+
public lookupValue = signal<any>(undefined);
|
|
66
|
+
public dialogValue = signal<any>(undefined);
|
|
67
|
+
public print = false;
|
|
68
|
+
|
|
69
|
+
// Messagebox
|
|
70
|
+
public showdialog = signal(false);
|
|
71
|
+
public titledialog = '';
|
|
72
|
+
public textdialog = '';
|
|
73
|
+
public showconfirm = false;
|
|
74
|
+
public dialogHeight = 0;
|
|
75
|
+
public dialogWidth = 0;
|
|
76
|
+
public dialogTop = 0;
|
|
77
|
+
public dialogLeft = 0;
|
|
78
|
+
|
|
79
|
+
// Lookup
|
|
80
|
+
public showlookup = signal(false);
|
|
81
|
+
public titlelookup = '';
|
|
82
|
+
public textlookup = '';
|
|
83
|
+
public lookupHeight = 0;
|
|
84
|
+
public lookupWidth = 0;
|
|
85
|
+
public lookupTop = 0;
|
|
86
|
+
public lookupLeft = 0;
|
|
87
|
+
public lookup = '';
|
|
88
|
+
public lookupfilter = '';
|
|
89
|
+
public hideNavigation = true;
|
|
90
|
+
public navCollapsed = false;
|
|
91
|
+
public scale = 0; // totalScale — propagated via [(scale)] to ModelItemComponent → GlobalService
|
|
92
|
+
public uiScale = 0; // chrome scale capped at 1: applied to #mainContainer
|
|
93
|
+
public hide = true;
|
|
94
|
+
|
|
95
|
+
/** Returns the split-pane pixel size for the navigation panel (0 when hidden). */
|
|
96
|
+
get navAreaSize(): number {
|
|
97
|
+
if (this.hideNavigation) return 0;
|
|
98
|
+
return this.navCollapsed ? 8 : 20;
|
|
99
|
+
}
|
|
100
|
+
/** Returns the split-pane pixel size for the content area (100% when nav is hidden). */
|
|
101
|
+
get contentAreaSize(): number {
|
|
102
|
+
if (this.hideNavigation) return 100;
|
|
103
|
+
return this.navCollapsed ? 92 : 80;
|
|
104
|
+
}
|
|
105
|
+
/** Returns the title string for the active model item. */
|
|
106
|
+
get modelTitle(): string {
|
|
107
|
+
return `${this.currentModel?.title ?? ''} ${this.gsv?.getExtendedDescription() ?? ''}`.trim();
|
|
108
|
+
}
|
|
109
|
+
/** Returns the CSS transform string that scales the SVG/form content area. */
|
|
110
|
+
get scaleTransform(): string {
|
|
111
|
+
return `scale(${this.uiScale})`;
|
|
112
|
+
}
|
|
113
|
+
public articleRendered = false;
|
|
114
|
+
|
|
115
|
+
/** Returns true when the AG-Grid panel should be hidden (no list view and no masterDetail split). */
|
|
116
|
+
get gridHidden(): boolean {
|
|
117
|
+
return !this.viewList && !this.currentModel?.masterDetail;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Returns 0 (transparent) until the article wrapper has been rendered, then 1 (opaque).
|
|
121
|
+
* For masterDetail models the grid is always visible alongside the article,
|
|
122
|
+
* so we never hide it during the article-render transition.
|
|
123
|
+
*/
|
|
124
|
+
get gridOpacity(): number {
|
|
125
|
+
if (this.currentModel?.masterDetail) return 1;
|
|
126
|
+
return this.articleRendered ? 1 : 0;
|
|
127
|
+
}
|
|
128
|
+
private destroyRef = inject(DestroyRef);
|
|
129
|
+
private _prevScaleKey = '';
|
|
130
|
+
public breadCrumbs: string[] = [];
|
|
131
|
+
|
|
132
|
+
readonly mainContainer = viewChild.required<ElementRef>('mainContainer');
|
|
133
|
+
readonly outerWrapper = viewChild.required<ElementRef>('outerWrapper');
|
|
134
|
+
readonly contentContainer =
|
|
135
|
+
viewChild.required<ElementRef>('contentContainer');
|
|
136
|
+
|
|
137
|
+
/** Checks whether scale inputs have changed and, if so, calls refreshScale(). */
|
|
138
|
+
ngAfterViewChecked() {
|
|
139
|
+
const el = this.outerWrapper().nativeElement;
|
|
140
|
+
const key = `${el.clientWidth}x${el.clientHeight}|${this.viewList}|${this.showlookup()}|${this.currentModel?.id ?? ''}`;
|
|
141
|
+
if (key !== this._prevScaleKey) {
|
|
142
|
+
this._prevScaleKey = key;
|
|
143
|
+
this.refreshScale();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Measures the article/SVG dimensions and the viewport to compute the CSS
|
|
149
|
+
* scale factor that fits the form inside the available content area.
|
|
150
|
+
*/
|
|
151
|
+
public refreshScale() {
|
|
152
|
+
const mc = this.mainContainer().nativeElement;
|
|
153
|
+
const cc = this.contentContainer().nativeElement;
|
|
154
|
+
const w = this.outerWrapper().nativeElement.clientWidth * 1.1;
|
|
155
|
+
if (w === 0) {
|
|
156
|
+
this.scale = 1;
|
|
157
|
+
this.uiScale = 1;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const modelItem = cc.querySelector('app-model-item');
|
|
162
|
+
|
|
163
|
+
if (modelItem === null) {
|
|
164
|
+
this.scale = 1;
|
|
165
|
+
this.uiScale = 1;
|
|
166
|
+
mc.style.width = '100%';
|
|
167
|
+
mc.style.height = '100%';
|
|
168
|
+
cc.style.transform = '';
|
|
169
|
+
cc.style.width = '';
|
|
170
|
+
cc.style.height = '';
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const article = cc.querySelector('article') as HTMLElement | null;
|
|
175
|
+
const gridHost = cc.querySelector('grid') as HTMLElement | null;
|
|
176
|
+
const agGrid = cc.querySelector('ag-grid-angular') as HTMLElement | null;
|
|
177
|
+
|
|
178
|
+
const md = this.currentModel?.masterDetail ?? 0;
|
|
179
|
+
const hasSvg = (this.currentModel?.svg?.length ?? 0) > 0;
|
|
180
|
+
|
|
181
|
+
// Use model's declared design width; fall back to SVG img width → scrollWidth
|
|
182
|
+
let ww = parseInt(this.currentModel?.width ?? '', 10) || 0;
|
|
183
|
+
if (ww === 0 && hasSvg) {
|
|
184
|
+
// When SVG is present, use the img's actual design width so scale = w/entity.width
|
|
185
|
+
const svgImg = cc.querySelector('#bkgwhite') as HTMLImageElement | null;
|
|
186
|
+
ww =
|
|
187
|
+
(svgImg
|
|
188
|
+
? parseInt(svgImg.style.width, 10) || svgImg.naturalWidth
|
|
189
|
+
: 0) || 0;
|
|
190
|
+
}
|
|
191
|
+
if (ww === 0) ww = (modelItem.children[0] as HTMLElement)?.scrollWidth ?? 0;
|
|
192
|
+
if (ww === 0) ww = w;
|
|
193
|
+
|
|
194
|
+
// totalScale: SVG is vector → fill the full available width; forms: never above 1
|
|
195
|
+
this.scale = hasSvg ? w / ww : Math.min(w / ww, 1);
|
|
196
|
+
// uiScale: chrome (toolbar/itemtab/itemdetail) — never above 1
|
|
197
|
+
this.uiScale = Math.min(this.scale, 1);
|
|
198
|
+
// contentExtra: extra scale applied only to article+grid (#contentContainer)
|
|
199
|
+
const contentExtra = this.uiScale > 0 ? this.scale / this.uiScale : 1;
|
|
200
|
+
|
|
201
|
+
// Expand mainContainer to compensate uiScale so it fills outerWrapper
|
|
202
|
+
mc.style.width = 100 / this.uiScale + '%';
|
|
203
|
+
mc.style.height = 100 / this.uiScale + '%';
|
|
204
|
+
|
|
205
|
+
// contentContainer: apply extra scale for SVG (> 1 only when ratio > 1 and SVG)
|
|
206
|
+
if (contentExtra > 1) {
|
|
207
|
+
cc.style.transform = `scale(${contentExtra})`;
|
|
208
|
+
cc.style.transformOrigin = '0 0';
|
|
209
|
+
cc.style.width = 100 / contentExtra + '%';
|
|
210
|
+
cc.style.height = 100 / contentExtra + '%';
|
|
211
|
+
} else {
|
|
212
|
+
cc.style.transform = '';
|
|
213
|
+
cc.style.width = '';
|
|
214
|
+
cc.style.height = '';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (article) {
|
|
218
|
+
if (this.viewList) {
|
|
219
|
+
// List view: hide the article so the grid occupies the full container.
|
|
220
|
+
article.style.position = 'fixed';
|
|
221
|
+
article.style.width = '0px';
|
|
222
|
+
article.style.height = '0px';
|
|
223
|
+
article.style.minHeight = '';
|
|
224
|
+
article.style.overflowY = '';
|
|
225
|
+
} else {
|
|
226
|
+
// Detail view: show the article at full width.
|
|
227
|
+
article.style.position = 'relative';
|
|
228
|
+
article.style.top = '0px';
|
|
229
|
+
article.style.width = '100%';
|
|
230
|
+
article.style.maxHeight = '';
|
|
231
|
+
article.style.overflowY = 'auto';
|
|
232
|
+
if (md > 0) {
|
|
233
|
+
// masterDetail: article takes top md%, grid takes the remainder.
|
|
234
|
+
article.style.height = md + '%';
|
|
235
|
+
article.style.minHeight = '50px';
|
|
236
|
+
} else {
|
|
237
|
+
article.style.height = 100 / contentExtra + '%';
|
|
238
|
+
article.style.minHeight = '';
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (gridHost) {
|
|
244
|
+
gridHost.style.width = '100%';
|
|
245
|
+
// In list view the article is hidden, so the grid takes the full height
|
|
246
|
+
// even when masterDetail is configured.
|
|
247
|
+
gridHost.style.height =
|
|
248
|
+
md > 0 && !this.viewList ? 100 - md + '%' : '100%';
|
|
249
|
+
}
|
|
250
|
+
if (agGrid) {
|
|
251
|
+
agGrid.style.opacity = this.showlookup() ? '0.1' : '0.9';
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** Computes the centred top/left position for a floating panel of given size. */
|
|
256
|
+
private centrePanel(h: number, w: number): { top: number; left: number } {
|
|
257
|
+
const s = this.scale || 1;
|
|
258
|
+
return {
|
|
259
|
+
top: Math.max(0, (window.innerHeight / s - h) / 2),
|
|
260
|
+
left: Math.max(0, (window.innerWidth / s - w) / 2),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@HostListener('window:resize')
|
|
265
|
+
/** HostListener: recalculates scale and re-centres dialog/lookup panels on window resize. */
|
|
266
|
+
public onResize() {
|
|
267
|
+
this._prevScaleKey = '';
|
|
268
|
+
this.refreshScale();
|
|
269
|
+
if (this.showdialog() && this.dialogWidth > 0 && this.dialogHeight > 0) {
|
|
270
|
+
({ top: this.dialogTop, left: this.dialogLeft } = this.centrePanel(
|
|
271
|
+
this.dialogHeight,
|
|
272
|
+
this.dialogWidth
|
|
273
|
+
));
|
|
274
|
+
}
|
|
275
|
+
if (this.showlookup() && this.lookupWidth > 0 && this.lookupHeight > 0) {
|
|
276
|
+
({ top: this.lookupTop, left: this.lookupLeft } = this.centrePanel(
|
|
277
|
+
this.lookupHeight,
|
|
278
|
+
this.lookupWidth
|
|
279
|
+
));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** Lifecycle: wires lookup, dialog, and grid-refresh subscriptions from GlobalService. */
|
|
284
|
+
public ngAfterViewInit() {
|
|
285
|
+
this.viewList = this.currentModel?.viewList ?? true;
|
|
286
|
+
this.gsv
|
|
287
|
+
.getLookupField()
|
|
288
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
289
|
+
.subscribe(lookup => this.setLookup(lookup));
|
|
290
|
+
this.gsv
|
|
291
|
+
.getDialogField()
|
|
292
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
293
|
+
.subscribe(dialog => this.setDialog(dialog));
|
|
294
|
+
this.gsv
|
|
295
|
+
.getGridRefresh()
|
|
296
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
297
|
+
.subscribe(() => {
|
|
298
|
+
this.refreshGrid = !this.refreshGrid;
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Applies lookup panel position/visibility state received from the child model item. */
|
|
303
|
+
public setLookup(lookup: LookupFieldInterface) {
|
|
304
|
+
this.showlookup.set(lookup.showlookup);
|
|
305
|
+
this.gsv.setModalActive(lookup.showlookup);
|
|
306
|
+
this.titlelookup = lookup.titlelookup;
|
|
307
|
+
this.textlookup = lookup.textlookup;
|
|
308
|
+
this.lookupHeight = lookup.lookupHeight;
|
|
309
|
+
this.lookupWidth = lookup.lookupWidth;
|
|
310
|
+
this.lookupTop = lookup.lookupTop;
|
|
311
|
+
this.lookupLeft = lookup.lookupLeft;
|
|
312
|
+
this.lookup = lookup.lookup;
|
|
313
|
+
this.lookupfilter = lookup.lookupfilter;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/** Applies dialog/messagebox position and visibility state received from the child model item. */
|
|
317
|
+
public setDialog(dialog: DialogFieldInterface) {
|
|
318
|
+
this.showdialog.set(dialog.showdialog);
|
|
319
|
+
this.gsv.setModalActive(dialog.showdialog);
|
|
320
|
+
this.titledialog = dialog.titledialog;
|
|
321
|
+
this.textdialog = dialog.textdialog;
|
|
322
|
+
this.showconfirm = dialog.showconfirm;
|
|
323
|
+
this.dialogHeight = dialog.dialogHeight;
|
|
324
|
+
this.dialogWidth = dialog.dialogWidth;
|
|
325
|
+
this.dialogTop = dialog.dialogTop;
|
|
326
|
+
this.dialogLeft = dialog.dialogLeft;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** Forwards dialog-close event to the child model item and clears local dialog state. */
|
|
330
|
+
public dialogResult(rsp: any) {
|
|
331
|
+
this.showdialog.set(false);
|
|
332
|
+
this.gsv.setModalActive(false);
|
|
333
|
+
this.dialogValue.set(rsp);
|
|
334
|
+
this.titledialog = '';
|
|
335
|
+
this.textdialog = '';
|
|
336
|
+
this.showconfirm = false;
|
|
337
|
+
this.dialogHeight = 0;
|
|
338
|
+
this.dialogWidth = 0;
|
|
339
|
+
this.dialogTop = 0;
|
|
340
|
+
this.dialogLeft = 0;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/** Forwards lookup-selection event to the child model item and clears local lookup state. */
|
|
344
|
+
public lookupResult(rsp: any) {
|
|
345
|
+
this.showlookup.set(false);
|
|
346
|
+
this.gsv.setModalActive(false);
|
|
347
|
+
this.lookupValue.set(rsp);
|
|
348
|
+
this.titlelookup = '';
|
|
349
|
+
this.textlookup = '';
|
|
350
|
+
this.lookupHeight = 0;
|
|
351
|
+
this.lookupWidth = 0;
|
|
352
|
+
this.lookupTop = 0;
|
|
353
|
+
this.lookupLeft = 0;
|
|
354
|
+
this.lookup = '';
|
|
355
|
+
this.lookupfilter = '';
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** Handles toolbar command updates emitted by the child article component. */
|
|
359
|
+
public commandsChanged(commands: ItemCommandInterface[]) {
|
|
360
|
+
if (commands) {
|
|
361
|
+
this.articleRendered = true;
|
|
362
|
+
this.commands = commands;
|
|
363
|
+
if (this.currentModel?.viewList && this.viewList) {
|
|
364
|
+
this.viewList = this.currentModel.viewList;
|
|
365
|
+
this.insertMode = commands.find(c => c.id === 'insertmode')!.state;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/** Dispatches toolbar actions (exit, print, viewState, etc.) to the active model item. */
|
|
371
|
+
public commandRaised(commandId: string) {
|
|
372
|
+
if (commandId === 'exit') {
|
|
373
|
+
this.gsv
|
|
374
|
+
.getProjectItems(
|
|
375
|
+
this.gsv.getProject().project + '.' + this.gsv.getProject().year
|
|
376
|
+
)
|
|
377
|
+
.forEach(item => {
|
|
378
|
+
item.loaded = false;
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
if (commandId !== 'viewState') {
|
|
382
|
+
if (this.viewList && commandId !== 'exit' && commandId !== 'print') {
|
|
383
|
+
this.viewList = false;
|
|
384
|
+
}
|
|
385
|
+
if (commandId === 'print') {
|
|
386
|
+
this.print = !this.print;
|
|
387
|
+
}
|
|
388
|
+
this.currentCommand = { id: commandId, state: true };
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/** Updates the active model reference, breadcrumbs, and view state on model navigation. */
|
|
393
|
+
public modelChanged(model: ItemInterface) {
|
|
394
|
+
this.breadCrumbs = [];
|
|
395
|
+
this.gsv.setExtendedDescription('');
|
|
396
|
+
try {
|
|
397
|
+
const origin = localStorage.getItem('origin');
|
|
398
|
+
if (origin) {
|
|
399
|
+
queueMicrotask(() => {
|
|
400
|
+
try {
|
|
401
|
+
localStorage.removeItem('origin');
|
|
402
|
+
|
|
403
|
+
const originParts = origin.split('.');
|
|
404
|
+
if (originParts.length < 3) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const projectKey = originParts.slice(0, 2).join('.');
|
|
409
|
+
const modelSource = this.gsv.getProjectItems(projectKey);
|
|
410
|
+
|
|
411
|
+
if (!modelSource) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const targetModel = modelSource.filter(
|
|
416
|
+
e => e.name === originParts[2]
|
|
417
|
+
)[0];
|
|
418
|
+
if (!targetModel) {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (originParts[3]) {
|
|
423
|
+
this.gsv.setCurrentFocus({ id: originParts[3], value: '' });
|
|
424
|
+
}
|
|
425
|
+
if (originParts[4]) {
|
|
426
|
+
this.gsv.setCurrentKeys(originParts[4]);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
this.modelChanged(targetModel);
|
|
430
|
+
} catch {
|
|
431
|
+
// origin parsing failed — continue silently
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
} else {
|
|
435
|
+
if (localStorage.length > 0) {
|
|
436
|
+
Object.keys(localStorage)
|
|
437
|
+
.filter(k => k.split('.').length > 4)
|
|
438
|
+
.sort(
|
|
439
|
+
(a, b) =>
|
|
440
|
+
parseInt(a.split('.')[0], 10) - parseInt(b.split('.')[0], 10)
|
|
441
|
+
)
|
|
442
|
+
.forEach(element => {
|
|
443
|
+
const parts = element.split('.');
|
|
444
|
+
this.breadCrumbs.push(parts[4]);
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
if (
|
|
448
|
+
this.previousModel &&
|
|
449
|
+
(this.previousModel.linkedItems?.[0]?.length ?? 1) === 0
|
|
450
|
+
) {
|
|
451
|
+
this.previousModel.loaded = false;
|
|
452
|
+
}
|
|
453
|
+
this.previousModel = this.currentModel;
|
|
454
|
+
if (
|
|
455
|
+
this.currentModel === undefined ||
|
|
456
|
+
model.id !== this.currentModel.id
|
|
457
|
+
) {
|
|
458
|
+
this.currentModel = model;
|
|
459
|
+
this.hide = false;
|
|
460
|
+
if (
|
|
461
|
+
this.currentModel.groupName === '' ||
|
|
462
|
+
this.previousModel === undefined ||
|
|
463
|
+
this.currentModel.groupName !== this.previousModel.groupName
|
|
464
|
+
) {
|
|
465
|
+
this.gsv.setCurrentLinkItem({
|
|
466
|
+
id: this.currentModel.id,
|
|
467
|
+
groupName: this.currentModel.groupName,
|
|
468
|
+
prg: this.currentModel.prgDim === 1 ? [1] : [1, 1],
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
this.viewList = model.viewList && !model.loaded;
|
|
473
|
+
}
|
|
474
|
+
} catch {
|
|
475
|
+
// modelChanged failed — continue silently
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/** Handles grid row selection or view-list toggle from the grid component. */
|
|
480
|
+
public viewChanged(changed: ViewListInterface) {
|
|
481
|
+
const hasRows = Array.isArray(changed.rows) && changed.rows.length > 0;
|
|
482
|
+
const isMasterDetail = this.currentModel?.masterDetail !== 0;
|
|
483
|
+
|
|
484
|
+
if ((this.viewList || isMasterDetail) && hasRows) {
|
|
485
|
+
// Row selected in the grid → navigate to that record's article view.
|
|
486
|
+
this.articleRendered = isMasterDetail; // keep grid visible for masterDetail
|
|
487
|
+
this.currentCommand = {
|
|
488
|
+
id: 'go:' + (changed.rows![0] as { _prg: string })._prg.replace(',', ';'),
|
|
489
|
+
state: true,
|
|
490
|
+
};
|
|
491
|
+
this.viewList = false;
|
|
492
|
+
} else if (!isMasterDetail) {
|
|
493
|
+
// Toggle back to list view (toolbar "table" button).
|
|
494
|
+
this.viewList = changed.state;
|
|
495
|
+
this.previousModel = this.currentModel;
|
|
496
|
+
this.currentCommand = { id: 'table', state: changed.state };
|
|
497
|
+
this.refreshGrid = !this.refreshGrid;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/** Toggles the navigation panel visibility. */
|
|
502
|
+
public navigationState(state: boolean) {
|
|
503
|
+
this.hideNavigation = state;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/** Toggles the navigation panel between collapsed and expanded. */
|
|
507
|
+
public navigationCollapsed(collapsed: boolean) {
|
|
508
|
+
this.navCollapsed = collapsed;
|
|
509
|
+
}
|
|
510
|
+
}
|