/
singletonlayout.ts
189 lines (168 loc) · 5.42 KB
/
singletonlayout.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
/*-----------------------------------------------------------------------------
| Copyright (c) 2014-2017, PhosphorJS Contributors
|
| Distributed under the terms of the BSD 3-Clause License.
|
| The full license is in the file LICENSE, distributed with this software.
|----------------------------------------------------------------------------*/
import { MessageLoop } from '@lumino/messaging';
import { Layout } from './layout';
import { Widget } from './widget';
/**
* A concrete layout implementation which holds a single widget.
*
* #### Notes
* This class is useful for creating simple container widgets which
* hold a single child. The child should be positioned with CSS.
*/
export class SingletonLayout extends Layout {
/**
* Dispose of the resources held by the layout.
*/
dispose(): void {
if (this._widget) {
let widget = this._widget;
this._widget = null;
widget.dispose();
}
super.dispose();
}
/**
* Get the child widget for the layout.
*/
get widget(): Widget | null {
return this._widget;
}
/**
* Set the child widget for the layout.
*
* #### Notes
* Setting the child widget will cause the old child widget to be
* automatically disposed. If that is not desired, set the parent
* of the old child to `null` before assigning a new child.
*/
set widget(widget: Widget | null) {
// Remove the widget from its current parent. This is a no-op
// if the widget's parent is already the layout parent widget.
if (widget) {
widget.parent = this.parent;
}
// Bail early if the widget does not change.
if (this._widget === widget) {
return;
}
// Dispose of the old child widget.
if (this._widget) {
this._widget.dispose();
}
// Update the internal widget.
this._widget = widget;
// Attach the new child widget if needed.
if (this.parent && widget) {
this.attachWidget(widget);
}
}
/**
* Create an iterator over the widgets in the layout.
*
* @returns A new iterator over the widgets in the layout.
*/
*[Symbol.iterator](): IterableIterator<Widget> {
if (this._widget) {
yield this._widget;
}
}
/**
* Remove a widget from the layout.
*
* @param widget - The widget to remove from the layout.
*
* #### Notes
* A widget is automatically removed from the layout when its `parent`
* is set to `null`. This method should only be invoked directly when
* removing a widget from a layout which has yet to be installed on a
* parent widget.
*
* This method does *not* modify the widget's `parent`.
*/
removeWidget(widget: Widget): void {
// Bail early if the widget does not exist in the layout.
if (this._widget !== widget) {
return;
}
// Clear the internal widget.
this._widget = null;
// If the layout is parented, detach the widget from the DOM.
if (this.parent) {
this.detachWidget(widget);
}
}
/**
* Perform layout initialization which requires the parent widget.
*/
protected init(): void {
super.init();
for (const widget of this) {
this.attachWidget(widget);
}
}
/**
* Attach a widget to the parent's DOM node.
*
* @param widget - The widget to attach to the parent.
*
* #### Notes
* This method is called automatically by the single layout at the
* appropriate time. It should not be called directly by user code.
*
* The default implementation adds the widgets's node to the parent's
* node at the proper location, and sends the appropriate attach
* messages to the widget if the parent is attached to the DOM.
*
* Subclasses may reimplement this method to control how the widget's
* node is added to the parent's node.
*/
protected attachWidget(widget: Widget): void {
// Send a `'before-attach'` message if the parent is attached.
if (this.parent!.isAttached) {
MessageLoop.sendMessage(widget, Widget.Msg.BeforeAttach);
}
// Add the widget's node to the parent.
this.parent!.node.appendChild(widget.node);
// Send an `'after-attach'` message if the parent is attached.
if (this.parent!.isAttached) {
MessageLoop.sendMessage(widget, Widget.Msg.AfterAttach);
}
}
/**
* Detach a widget from the parent's DOM node.
*
* @param widget - The widget to detach from the parent.
*
* #### Notes
* This method is called automatically by the single layout at the
* appropriate time. It should not be called directly by user code.
*
* The default implementation removes the widget's node from the
* parent's node, and sends the appropriate detach messages to the
* widget if the parent is attached to the DOM.
*
* Subclasses may reimplement this method to control how the widget's
* node is removed from the parent's node.
*/
protected detachWidget(widget: Widget): void {
// Send a `'before-detach'` message if the parent is attached.
if (this.parent!.isAttached) {
MessageLoop.sendMessage(widget, Widget.Msg.BeforeDetach);
}
// Remove the widget's node from the parent.
this.parent!.node.removeChild(widget.node);
// Send an `'after-detach'` message if the parent is attached.
if (this.parent!.isAttached) {
MessageLoop.sendMessage(widget, Widget.Msg.AfterDetach);
}
}
private _widget: Widget | null = null;
}