1 |
|
2 |
|
3 |
|
4 |
|
5 | import { Signal } from '@lumino/signaling';
|
6 | import { AttachmentsModel } from '@jupyterlab/attachments';
|
7 | import { CodeEditor } from '@jupyterlab/codeeditor';
|
8 | import { OutputAreaModel } from '@jupyterlab/outputarea';
|
9 | import { createMutex, createStandaloneCell } from '@jupyter/ydoc';
|
10 | const globalModelDBMutex = createMutex();
|
11 | export function isCodeCellModel(model) {
|
12 | return model.type === 'code';
|
13 | }
|
14 | export function isMarkdownCellModel(model) {
|
15 | return model.type === 'markdown';
|
16 | }
|
17 | export function isRawCellModel(model) {
|
18 | return model.type === 'raw';
|
19 | }
|
20 |
|
21 |
|
22 |
|
23 | export class CellModel extends CodeEditor.Model {
|
24 | constructor(options = {}) {
|
25 | const { cell_type, sharedModel, ...others } = options;
|
26 | super({
|
27 | sharedModel: sharedModel !== null && sharedModel !== void 0 ? sharedModel : createStandaloneCell({
|
28 | cell_type: cell_type !== null && cell_type !== void 0 ? cell_type : 'raw',
|
29 | id: options.id
|
30 | }),
|
31 | ...others
|
32 | });
|
33 | |
34 |
|
35 |
|
36 | this.contentChanged = new Signal(this);
|
37 | |
38 |
|
39 |
|
40 | this.stateChanged = new Signal(this);
|
41 | this._metadataChanged = new Signal(this);
|
42 | this._trusted = false;
|
43 | this.standaloneModel = typeof options.sharedModel === 'undefined';
|
44 | this.trusted = !!this.getMetadata('trusted') || !!options.trusted;
|
45 | this.sharedModel.changed.connect(this.onGenericChange, this);
|
46 | this.sharedModel.metadataChanged.connect(this._onMetadataChanged, this);
|
47 | }
|
48 | |
49 |
|
50 |
|
51 | get metadataChanged() {
|
52 | return this._metadataChanged;
|
53 | }
|
54 | |
55 |
|
56 |
|
57 | get id() {
|
58 | return this.sharedModel.getId();
|
59 | }
|
60 | |
61 |
|
62 |
|
63 | get metadata() {
|
64 | return this.sharedModel.metadata;
|
65 | }
|
66 | |
67 |
|
68 |
|
69 | get trusted() {
|
70 | return this._trusted;
|
71 | }
|
72 | set trusted(newValue) {
|
73 | const oldValue = this.trusted;
|
74 | if (oldValue !== newValue) {
|
75 | this._trusted = newValue;
|
76 | this.onTrustedChanged(this, { newValue, oldValue });
|
77 | }
|
78 | }
|
79 | |
80 |
|
81 |
|
82 | dispose() {
|
83 | if (this.isDisposed) {
|
84 | return;
|
85 | }
|
86 | this.sharedModel.changed.disconnect(this.onGenericChange, this);
|
87 | this.sharedModel.metadataChanged.disconnect(this._onMetadataChanged, this);
|
88 | super.dispose();
|
89 | }
|
90 | |
91 |
|
92 |
|
93 |
|
94 |
|
95 | onTrustedChanged(trusted, args) {
|
96 |
|
97 | }
|
98 | |
99 |
|
100 |
|
101 |
|
102 |
|
103 | deleteMetadata(key) {
|
104 | return this.sharedModel.deleteMetadata(key);
|
105 | }
|
106 | |
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 | getMetadata(key) {
|
115 | return this.sharedModel.getMetadata(key);
|
116 | }
|
117 | |
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 | setMetadata(key, value) {
|
124 | if (typeof value === 'undefined') {
|
125 | this.sharedModel.deleteMetadata(key);
|
126 | }
|
127 | else {
|
128 | this.sharedModel.setMetadata(key, value);
|
129 | }
|
130 | }
|
131 | |
132 |
|
133 |
|
134 | toJSON() {
|
135 | return this.sharedModel.toJSON();
|
136 | }
|
137 | |
138 |
|
139 |
|
140 | onGenericChange() {
|
141 | this.contentChanged.emit(void 0);
|
142 | }
|
143 | _onMetadataChanged(sender, change) {
|
144 | this._metadataChanged.emit(change);
|
145 | }
|
146 | }
|
147 |
|
148 |
|
149 |
|
150 | export class AttachmentsCellModel extends CellModel {
|
151 | |
152 |
|
153 |
|
154 | constructor(options) {
|
155 | var _a;
|
156 | super(options);
|
157 | const factory = (_a = options.contentFactory) !== null && _a !== void 0 ? _a : AttachmentsCellModel.defaultContentFactory;
|
158 | const values = this.sharedModel.getAttachments();
|
159 | this._attachments = factory.createAttachmentsModel({ values });
|
160 | this._attachments.stateChanged.connect(this.onGenericChange, this);
|
161 | this._attachments.changed.connect(this._onAttachmentsChange, this);
|
162 | this.sharedModel.changed.connect(this._onSharedModelChanged, this);
|
163 | }
|
164 | |
165 |
|
166 |
|
167 | get attachments() {
|
168 | return this._attachments;
|
169 | }
|
170 | |
171 |
|
172 |
|
173 | dispose() {
|
174 | if (this.isDisposed) {
|
175 | return;
|
176 | }
|
177 | this._attachments.stateChanged.disconnect(this.onGenericChange, this);
|
178 | this._attachments.changed.disconnect(this._onAttachmentsChange, this);
|
179 | this._attachments.dispose();
|
180 | this.sharedModel.changed.disconnect(this._onSharedModelChanged, this);
|
181 | super.dispose();
|
182 | }
|
183 | |
184 |
|
185 |
|
186 | toJSON() {
|
187 | return super.toJSON();
|
188 | }
|
189 | |
190 |
|
191 |
|
192 | _onAttachmentsChange(sender, event) {
|
193 | const cell = this.sharedModel;
|
194 | globalModelDBMutex(() => cell.setAttachments(sender.toJSON()));
|
195 | }
|
196 | |
197 |
|
198 |
|
199 | _onSharedModelChanged(slot, change) {
|
200 | if (change.attachmentsChange) {
|
201 | const cell = this.sharedModel;
|
202 | globalModelDBMutex(() => { var _a; return this._attachments.fromJSON((_a = cell.getAttachments()) !== null && _a !== void 0 ? _a : {}); });
|
203 | }
|
204 | }
|
205 | }
|
206 |
|
207 |
|
208 |
|
209 | (function (AttachmentsCellModel) {
|
210 | |
211 |
|
212 |
|
213 | class ContentFactory {
|
214 | |
215 |
|
216 |
|
217 | createAttachmentsModel(options) {
|
218 | return new AttachmentsModel(options);
|
219 | }
|
220 | }
|
221 | AttachmentsCellModel.ContentFactory = ContentFactory;
|
222 | |
223 |
|
224 |
|
225 | AttachmentsCellModel.defaultContentFactory = new ContentFactory();
|
226 | })(AttachmentsCellModel || (AttachmentsCellModel = {}));
|
227 |
|
228 |
|
229 |
|
230 | export class RawCellModel extends AttachmentsCellModel {
|
231 | |
232 |
|
233 |
|
234 | constructor(options = {}) {
|
235 | super({
|
236 | cell_type: 'raw',
|
237 | ...options
|
238 | });
|
239 | }
|
240 | |
241 |
|
242 |
|
243 | get type() {
|
244 | return 'raw';
|
245 | }
|
246 | |
247 |
|
248 |
|
249 | toJSON() {
|
250 | return super.toJSON();
|
251 | }
|
252 | }
|
253 |
|
254 |
|
255 |
|
256 | export class MarkdownCellModel extends AttachmentsCellModel {
|
257 | |
258 |
|
259 |
|
260 | constructor(options = {}) {
|
261 | super({
|
262 | cell_type: 'markdown',
|
263 | ...options
|
264 | });
|
265 |
|
266 | this.mimeType = 'text/x-ipythongfm';
|
267 | }
|
268 | |
269 |
|
270 |
|
271 | get type() {
|
272 | return 'markdown';
|
273 | }
|
274 | |
275 |
|
276 |
|
277 | toJSON() {
|
278 | return super.toJSON();
|
279 | }
|
280 | }
|
281 |
|
282 |
|
283 |
|
284 | export class CodeCellModel extends CellModel {
|
285 | |
286 |
|
287 |
|
288 | constructor(options = {}) {
|
289 | var _a;
|
290 | super({
|
291 | cell_type: 'code',
|
292 | ...options
|
293 | });
|
294 | this._executedCode = '';
|
295 | this._isDirty = false;
|
296 | const factory = (_a = options === null || options === void 0 ? void 0 : options.contentFactory) !== null && _a !== void 0 ? _a : CodeCellModel.defaultContentFactory;
|
297 | const trusted = this.trusted;
|
298 | const outputs = this.sharedModel.getOutputs();
|
299 | this._outputs = factory.createOutputArea({ trusted, values: outputs });
|
300 | this.sharedModel.changed.connect(this._onSharedModelChanged, this);
|
301 | this._outputs.changed.connect(this.onGenericChange, this);
|
302 | this._outputs.changed.connect(this.onOutputsChange, this);
|
303 | }
|
304 | |
305 |
|
306 |
|
307 | get type() {
|
308 | return 'code';
|
309 | }
|
310 | |
311 |
|
312 |
|
313 | get executionCount() {
|
314 | return this.sharedModel.execution_count || null;
|
315 | }
|
316 | set executionCount(newValue) {
|
317 | this.sharedModel.execution_count = newValue || null;
|
318 | }
|
319 | |
320 |
|
321 |
|
322 |
|
323 |
|
324 |
|
325 | get isDirty() {
|
326 |
|
327 |
|
328 | return this._isDirty;
|
329 | }
|
330 | |
331 |
|
332 |
|
333 | get outputs() {
|
334 | return this._outputs;
|
335 | }
|
336 | clearExecution() {
|
337 | this.outputs.clear();
|
338 | this.executionCount = null;
|
339 | this._setDirty(false);
|
340 | this.sharedModel.deleteMetadata('execution');
|
341 |
|
342 | this.trusted = true;
|
343 | }
|
344 | |
345 |
|
346 |
|
347 | dispose() {
|
348 | if (this.isDisposed) {
|
349 | return;
|
350 | }
|
351 | this.sharedModel.changed.disconnect(this._onSharedModelChanged, this);
|
352 | this._outputs.changed.disconnect(this.onGenericChange, this);
|
353 | this._outputs.changed.disconnect(this.onOutputsChange, this);
|
354 | this._outputs.dispose();
|
355 | this._outputs = null;
|
356 | super.dispose();
|
357 | }
|
358 | |
359 |
|
360 |
|
361 | onTrustedChanged(trusted, args) {
|
362 | const newTrusted = args.newValue;
|
363 | if (this._outputs) {
|
364 | this._outputs.trusted = newTrusted;
|
365 | }
|
366 | if (newTrusted) {
|
367 | const codeCell = this.sharedModel;
|
368 | const metadata = codeCell.getMetadata();
|
369 | metadata.trusted = true;
|
370 | codeCell.setMetadata(metadata);
|
371 | }
|
372 | this.stateChanged.emit({
|
373 | name: 'trusted',
|
374 | oldValue: args.oldValue,
|
375 | newValue: newTrusted
|
376 | });
|
377 | }
|
378 | |
379 |
|
380 |
|
381 | toJSON() {
|
382 | return super.toJSON();
|
383 | }
|
384 | |
385 |
|
386 |
|
387 | onOutputsChange(sender, event) {
|
388 | const codeCell = this.sharedModel;
|
389 | globalModelDBMutex(() => {
|
390 | switch (event.type) {
|
391 | case 'add': {
|
392 | const outputs = event.newValues.map(output => output.toJSON());
|
393 | codeCell.updateOutputs(event.newIndex, event.newIndex, outputs);
|
394 | break;
|
395 | }
|
396 | case 'set': {
|
397 | const newValues = event.newValues.map(output => output.toJSON());
|
398 | codeCell.updateOutputs(event.oldIndex, event.oldIndex + newValues.length, newValues);
|
399 | break;
|
400 | }
|
401 | case 'remove':
|
402 | codeCell.updateOutputs(event.oldIndex, event.oldValues.length);
|
403 | break;
|
404 | default:
|
405 | throw new Error(`Invalid event type: ${event.type}`);
|
406 | }
|
407 | });
|
408 | }
|
409 | |
410 |
|
411 |
|
412 | _onSharedModelChanged(slot, change) {
|
413 | if (change.outputsChange) {
|
414 | globalModelDBMutex(() => {
|
415 | this.outputs.clear();
|
416 | slot.getOutputs().forEach(output => this._outputs.add(output));
|
417 | });
|
418 | }
|
419 | if (change.executionCountChange) {
|
420 | if (change.executionCountChange.newValue &&
|
421 | (this.isDirty || !change.executionCountChange.oldValue)) {
|
422 | this._setDirty(false);
|
423 | }
|
424 | this.stateChanged.emit({
|
425 | name: 'executionCount',
|
426 | oldValue: change.executionCountChange.oldValue,
|
427 | newValue: change.executionCountChange.newValue
|
428 | });
|
429 | }
|
430 | if (change.sourceChange && this.executionCount !== null) {
|
431 | this._setDirty(this._executedCode !== this.sharedModel.getSource().trim());
|
432 | }
|
433 | }
|
434 | |
435 |
|
436 |
|
437 | _setDirty(v) {
|
438 | if (!v) {
|
439 | this._executedCode = this.sharedModel.getSource().trim();
|
440 | }
|
441 | if (v !== this._isDirty) {
|
442 | this._isDirty = v;
|
443 | this.stateChanged.emit({
|
444 | name: 'isDirty',
|
445 | oldValue: !v,
|
446 | newValue: v
|
447 | });
|
448 | }
|
449 | }
|
450 | }
|
451 |
|
452 |
|
453 |
|
454 | (function (CodeCellModel) {
|
455 | |
456 |
|
457 |
|
458 | class ContentFactory {
|
459 | |
460 |
|
461 |
|
462 | createOutputArea(options) {
|
463 | return new OutputAreaModel(options);
|
464 | }
|
465 | }
|
466 | CodeCellModel.ContentFactory = ContentFactory;
|
467 | |
468 |
|
469 |
|
470 | CodeCellModel.defaultContentFactory = new ContentFactory();
|
471 | })(CodeCellModel || (CodeCellModel = {}));
|
472 |
|
\ | No newline at end of file |