1 | import { ObservableList } from '@jupyterlab/observables';
|
2 | import { SettingRegistry } from '@jupyterlab/settingregistry';
|
3 | import { findIndex, toArray } from '@lumino/algorithm';
|
4 | import { JSONExt } from '@lumino/coreutils';
|
5 | import { Dialog, showDialog } from '../dialog';
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | const DEFAULT_TOOLBAR_ITEM_RANK = 50;
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | async function displayInformation(trans) {
|
19 | const result = await showDialog({
|
20 | title: trans.__('Information'),
|
21 | body: trans.__('Toolbar customization has changed. You will need to reload JupyterLab to see the changes.'),
|
22 | buttons: [
|
23 | Dialog.cancelButton(),
|
24 | Dialog.okButton({ label: trans.__('Reload') })
|
25 | ]
|
26 | });
|
27 | if (result.button.accept) {
|
28 | location.reload();
|
29 | }
|
30 | }
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 | async function setToolbarItems(toolbarItems, registry, factoryName, pluginId, translator, propertyId = 'toolbar') {
|
45 | var _a;
|
46 | const trans = translator.load('jupyterlab');
|
47 | let canonical;
|
48 | let loaded = {};
|
49 | |
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 | function populate(schema) {
|
56 | var _a, _b;
|
57 | loaded = {};
|
58 | const pluginDefaults = Object.keys(registry.plugins)
|
59 | .map(plugin => {
|
60 | var _a, _b;
|
61 | const items = (_b = ((_a = registry.plugins[plugin].schema['jupyter.lab.toolbars']) !== null && _a !== void 0 ? _a : {})[factoryName]) !== null && _b !== void 0 ? _b : [];
|
62 | loaded[plugin] = items;
|
63 | return items;
|
64 | })
|
65 | .concat([(_b = ((_a = schema['jupyter.lab.toolbars']) !== null && _a !== void 0 ? _a : {})[factoryName]) !== null && _b !== void 0 ? _b : []])
|
66 | .reduceRight((acc, val) => SettingRegistry.reconcileToolbarItems(acc, val, true), []);
|
67 |
|
68 |
|
69 |
|
70 | schema.properties[propertyId].default = SettingRegistry.reconcileToolbarItems(pluginDefaults, schema.properties[propertyId].default, true).sort((a, b) => {
|
71 | var _a, _b;
|
72 | return ((_a = a.rank) !== null && _a !== void 0 ? _a : DEFAULT_TOOLBAR_ITEM_RANK) -
|
73 | ((_b = b.rank) !== null && _b !== void 0 ? _b : DEFAULT_TOOLBAR_ITEM_RANK);
|
74 | });
|
75 | }
|
76 |
|
77 | registry.transform(pluginId, {
|
78 | compose: plugin => {
|
79 | var _a, _b, _c, _d, _e;
|
80 |
|
81 | if (!canonical) {
|
82 | canonical = JSONExt.deepCopy(plugin.schema);
|
83 | populate(canonical);
|
84 | }
|
85 | const defaults = (_c = ((_b = ((_a = canonical.properties) !== null && _a !== void 0 ? _a : {})[propertyId]) !== null && _b !== void 0 ? _b : {}).default) !== null && _c !== void 0 ? _c : [];
|
86 |
|
87 | const user = plugin.data.user;
|
88 | const composite = plugin.data.composite;
|
89 |
|
90 | user[propertyId] = (_d = plugin.data.user[propertyId]) !== null && _d !== void 0 ? _d : [];
|
91 | composite[propertyId] = ((_e = SettingRegistry.reconcileToolbarItems(defaults, user[propertyId], false)) !== null && _e !== void 0 ? _e : []).sort((a, b) => {
|
92 | var _a, _b;
|
93 | return ((_a = a.rank) !== null && _a !== void 0 ? _a : DEFAULT_TOOLBAR_ITEM_RANK) -
|
94 | ((_b = b.rank) !== null && _b !== void 0 ? _b : DEFAULT_TOOLBAR_ITEM_RANK);
|
95 | });
|
96 | plugin.data = { composite, user };
|
97 | return plugin;
|
98 | },
|
99 | fetch: plugin => {
|
100 |
|
101 | if (!canonical) {
|
102 | canonical = JSONExt.deepCopy(plugin.schema);
|
103 | populate(canonical);
|
104 | }
|
105 | return {
|
106 | data: plugin.data,
|
107 | id: plugin.id,
|
108 | raw: plugin.raw,
|
109 | schema: canonical,
|
110 | version: plugin.version
|
111 | };
|
112 | }
|
113 | });
|
114 |
|
115 |
|
116 | canonical = null;
|
117 | const settings = await registry.load(pluginId);
|
118 |
|
119 | settings.changed.connect(() => {
|
120 | var _a;
|
121 | const newItems = (_a = settings.composite[propertyId]) !== null && _a !== void 0 ? _a : [];
|
122 | transferSettings(newItems);
|
123 | });
|
124 |
|
125 | registry.pluginChanged.connect(async (sender, plugin) => {
|
126 | var _a, _b, _c, _d;
|
127 |
|
128 |
|
129 |
|
130 |
|
131 | if (plugin !== pluginId) {
|
132 |
|
133 | const oldItems = (_a = loaded[plugin]) !== null && _a !== void 0 ? _a : [];
|
134 | const newItems = (_c = ((_b = registry.plugins[plugin].schema['jupyter.lab.toolbars']) !== null && _b !== void 0 ? _b : {})[factoryName]) !== null && _c !== void 0 ? _c : [];
|
135 | if (!JSONExt.deepEqual(oldItems, newItems)) {
|
136 | if (loaded[plugin]) {
|
137 |
|
138 | await displayInformation(trans);
|
139 | }
|
140 | else {
|
141 |
|
142 | loaded[plugin] = JSONExt.deepCopy(newItems);
|
143 | const newList = ((_d = SettingRegistry.reconcileToolbarItems(toArray(toolbarItems), newItems, false)) !== null && _d !== void 0 ? _d : []).sort((a, b) => {
|
144 | var _a, _b;
|
145 | return ((_a = a.rank) !== null && _a !== void 0 ? _a : DEFAULT_TOOLBAR_ITEM_RANK) -
|
146 | ((_b = b.rank) !== null && _b !== void 0 ? _b : DEFAULT_TOOLBAR_ITEM_RANK);
|
147 | });
|
148 | transferSettings(newList);
|
149 | }
|
150 | }
|
151 | }
|
152 | });
|
153 | const transferSettings = (newItems) => {
|
154 |
|
155 |
|
156 |
|
157 | toolbarItems.clear();
|
158 | toolbarItems.pushAll(newItems.filter(item => !item.disabled));
|
159 | };
|
160 |
|
161 | transferSettings((_a = settings.composite[propertyId]) !== null && _a !== void 0 ? _a : []);
|
162 | }
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 | export function createToolbarFactory(toolbarRegistry, settingsRegistry, factoryName, pluginId, translator, propertyId = 'toolbar') {
|
176 | const items = new ObservableList({
|
177 | itemCmp: (a, b) => JSONExt.deepEqual(a, b)
|
178 | });
|
179 |
|
180 | setToolbarItems(items, settingsRegistry, factoryName, pluginId, translator, propertyId).catch(reason => {
|
181 | console.error(`Failed to load toolbar items for factory ${factoryName} from ${pluginId}`, reason);
|
182 | });
|
183 | return (widget) => {
|
184 | const updateToolbar = (list, change) => {
|
185 | switch (change.type) {
|
186 | case 'move':
|
187 | toolbar.move(change.oldIndex, change.newIndex);
|
188 | break;
|
189 | case 'add':
|
190 | change.newValues.forEach(item => toolbar.push({
|
191 | name: item.name,
|
192 | widget: toolbarRegistry.createWidget(factoryName, widget, item)
|
193 | }));
|
194 | break;
|
195 | case 'remove':
|
196 | change.oldValues.forEach(() => toolbar.remove(change.oldIndex));
|
197 | break;
|
198 | case 'set':
|
199 | change.newValues.forEach(item => toolbar.set(change.newIndex, {
|
200 | name: item.name,
|
201 | widget: toolbarRegistry.createWidget(factoryName, widget, item)
|
202 | }));
|
203 | break;
|
204 | }
|
205 | };
|
206 | const toolbar = new ObservableList({
|
207 | values: toArray(items).map(item => {
|
208 | return {
|
209 | name: item.name,
|
210 | widget: toolbarRegistry.createWidget(factoryName, widget, item)
|
211 | };
|
212 | })
|
213 | });
|
214 | items.changed.connect(updateToolbar);
|
215 | widget.disposed.connect(() => {
|
216 | items.changed.disconnect(updateToolbar);
|
217 | });
|
218 | return toolbar;
|
219 | };
|
220 | }
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 | export function setToolbar(widget, factory) {
|
228 | if (!widget.toolbar) {
|
229 | console.log(`Widget ${widget.id} has no 'toolbar'.`);
|
230 | return;
|
231 | }
|
232 | const items = factory(widget);
|
233 | if (Array.isArray(items)) {
|
234 | items.forEach(({ name, widget: item }) => {
|
235 | widget.toolbar.addItem(name, item);
|
236 | });
|
237 | }
|
238 | else {
|
239 | const updateToolbar = (list, changes) => {
|
240 | switch (changes.type) {
|
241 | case 'add':
|
242 | changes.newValues.forEach((item, index) => {
|
243 | widget.toolbar.insertItem(changes.newIndex + index, item.name, item.widget);
|
244 | });
|
245 | break;
|
246 | case 'move':
|
247 | changes.oldValues.forEach(item => {
|
248 | item.widget.parent = null;
|
249 | });
|
250 | changes.newValues.forEach((item, index) => {
|
251 | widget.toolbar.insertItem(changes.newIndex + index, item.name, item.widget);
|
252 | });
|
253 | break;
|
254 | case 'remove':
|
255 | changes.oldValues.forEach(item => {
|
256 | item.widget.parent = null;
|
257 | });
|
258 | break;
|
259 | case 'set':
|
260 | changes.oldValues.forEach(item => {
|
261 | item.widget.parent = null;
|
262 | });
|
263 | changes.newValues.forEach((item, index) => {
|
264 | const existingIndex = findIndex(widget.toolbar.names(), name => item.name === name);
|
265 | if (existingIndex >= 0) {
|
266 | toArray(widget.toolbar.children())[existingIndex].parent = null;
|
267 | }
|
268 | widget.toolbar.insertItem(changes.newIndex + index, item.name, item.widget);
|
269 | });
|
270 | break;
|
271 | }
|
272 | };
|
273 | updateToolbar(items, {
|
274 | newIndex: 0,
|
275 | newValues: toArray(items),
|
276 | oldIndex: 0,
|
277 | oldValues: [],
|
278 | type: 'add'
|
279 | });
|
280 | items.changed.connect(updateToolbar);
|
281 | widget.disposed.connect(() => {
|
282 | items.changed.disconnect(updateToolbar);
|
283 | });
|
284 | }
|
285 | }
|
286 |
|
\ | No newline at end of file |