Skip to content

Commit f3b2de0

Browse files
Remove Evented from ListContent (#2619)
1 parent dcccb7b commit f3b2de0

File tree

5 files changed

+157
-133
lines changed

5 files changed

+157
-133
lines changed

app/components/list-content.hbs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
class="list-content js-list-content"
33
style={{this.style}}
44
{{did-insert this.elementInserted}}
5+
...attributes
56
>
67
<div class="list-table-container">
78
<table>
89
<colgroup>
9-
{{#each this.columns as |column|}}
10+
{{#each @columns as |column|}}
1011
<col style={{build-style width=(concat column.width "px")}} />
1112
{{/each}}
1213
</colgroup>

app/components/list-content.js

-130
This file was deleted.

app/components/list-content.ts

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import { action } from '@ember/object';
2+
import { addListener, removeListener, sendEvent } from '@ember/object/events';
3+
import { inject as service } from '@ember/service';
4+
import Component from '@glimmer/component';
5+
import { htmlSafe } from '@ember/template';
6+
import { schedule } from '@ember/runloop';
7+
import { tracked } from '@glimmer/tracking';
8+
import type { AnyFn } from 'ember/-private/type-utils';
9+
10+
import type LayoutService from '../services/layout';
11+
12+
interface ListContentSignature {
13+
Element: HTMLDivElement;
14+
Args: {
15+
/**
16+
* Array of objects representing the columns to render
17+
* and their corresponding widths. This array is passed
18+
* through the template.
19+
*
20+
* Each item in the array has `width` and `id` properties.
21+
*/
22+
columns: Array<{ id: string; width: number }>;
23+
/**
24+
* Number passed from `list`. Indicates the header height
25+
* in pixels.
26+
*/
27+
headerHeight: number;
28+
};
29+
}
30+
31+
/**
32+
* Base list view config
33+
*/
34+
export default class ListContent extends Component<ListContentSignature> {
35+
/**
36+
* The layout service. Used to observe the app's content height.
37+
*/
38+
@service('layout') declare layoutService: LayoutService;
39+
40+
@tracked contentHeight: number | null = null;
41+
42+
/**
43+
* Hook called before destruction. Clean up events listeners.
44+
*/
45+
willDestroy() {
46+
this.layoutService.off(
47+
'content-height-update',
48+
this,
49+
this.updateContentHeight,
50+
);
51+
return super.willDestroy();
52+
}
53+
54+
get height() {
55+
// In testing list-view is created before `contentHeight` is set
56+
// which will trigger an exception
57+
if (!this.contentHeight) {
58+
return 1;
59+
}
60+
return this.contentHeight - this.args.headerHeight;
61+
}
62+
63+
get style() {
64+
return htmlSafe(`height:${this.height}px`);
65+
}
66+
67+
/**
68+
* Hook called when content element is inserted.
69+
*/
70+
@action
71+
elementInserted() {
72+
schedule('afterRender', this, this.setupHeight);
73+
}
74+
75+
/**
76+
* Set up the content height and listen to any updates to that property.
77+
*/
78+
@action
79+
setupHeight() {
80+
this.contentHeight = this.layoutService.contentHeight;
81+
this.layoutService.on(
82+
'content-height-update',
83+
this,
84+
this.updateContentHeight,
85+
);
86+
}
87+
88+
/**
89+
* Triggered whenever the app's content height changes. This usually happens
90+
* when the window is resized. Once we detect a change we update this
91+
* component's `contentHeight` property and consequently its `height` style.
92+
*
93+
* @param height The app's new content height
94+
*/
95+
@action
96+
updateContentHeight(height: number) {
97+
this.contentHeight = height;
98+
}
99+
100+
// Manually implement Evented functionality, so we can move away from the mixin
101+
// TODO: Do we even need any evented-like things in this component?
102+
103+
on(eventName: string, method: AnyFn): void;
104+
on(eventName: string, target: unknown, method: AnyFn): void;
105+
106+
@action
107+
on(eventName: string, targetOrMethod: unknown | AnyFn, method?: AnyFn): void {
108+
if (typeof targetOrMethod === 'function') {
109+
// If we did not pass a target, default to `this`
110+
addListener(this, eventName, this, targetOrMethod as AnyFn);
111+
} else {
112+
addListener(this, eventName, targetOrMethod, method!);
113+
}
114+
}
115+
116+
one(eventName: string, method: AnyFn): void;
117+
one(eventName: string, target: unknown, method: AnyFn): void;
118+
119+
@action
120+
one(eventName: string, targetOrMethod: unknown | AnyFn, method?: AnyFn) {
121+
if (typeof targetOrMethod === 'function') {
122+
// If we did not pass a target, default to `this`
123+
addListener(this, eventName, this, targetOrMethod as AnyFn, true);
124+
} else {
125+
addListener(this, eventName, targetOrMethod, method!, true);
126+
}
127+
}
128+
129+
off(eventName: string, method: AnyFn): void;
130+
off(eventName: string, target: unknown, method: AnyFn): void;
131+
132+
@action
133+
off(eventName: string, targetOrMethod: unknown | AnyFn, method?: AnyFn) {
134+
try {
135+
if (typeof targetOrMethod === 'function') {
136+
// If we did not pass a target, default to `this`
137+
removeListener(this, eventName, this, targetOrMethod as AnyFn);
138+
} else {
139+
removeListener(this, eventName, targetOrMethod, method!);
140+
}
141+
} catch (e) {
142+
console.error(e);
143+
}
144+
}
145+
146+
@action
147+
trigger(eventName: string, ...args: Array<any>) {
148+
sendEvent(this, eventName, args);
149+
}
150+
}

app/controllers/container-types/index.js app/controllers/container-types/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import Controller from '@ember/controller';
22
import { action } from '@ember/object';
3+
import type RouterService from '@ember/routing/router-service';
34
import { inject as service } from '@ember/service';
45

6+
import type PortService from '../../services/port';
7+
58
export default class ContainerTypesIndexController extends Controller {
6-
@service port;
7-
@service router;
9+
@service declare port: PortService;
10+
@service declare router: RouterService;
811

912
@action
1013
refresh() {
File renamed without changes.

0 commit comments

Comments
 (0)