123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923 |
- /* -----------------------------------------------------------------------------
- | Copyright (c) Jupyter Development Team.
- | Distributed under the terms of the Modified BSD License.
- |----------------------------------------------------------------------------*/
- import { ISignal, Signal } from '@lumino/signaling';
- import { UUID } from '@lumino/coreutils';
- import * as Y from 'yjs';
- import * as nbformat from '@jupyterlab/nbformat';
- import * as models from './api';
- import { Delta } from './api';
- import { Awareness } from 'y-protocols/awareness';
- const deepCopy = (o: any) => JSON.parse(JSON.stringify(o));
- /**
- * Abstract interface to define Shared Models that can be bound to a text editor using any existing
- * Yjs-based editor binding.
- */
- export interface IYText extends models.ISharedText {
- readonly ysource: Y.Text;
- readonly awareness: Awareness | null;
- readonly undoManager: Y.UndoManager | null;
- }
- export type YCellType = YRawCell | YCodeCell | YMarkdownCell;
- export class YDocument<T> implements models.ISharedDocument {
- /**
- * Perform a transaction. While the function f is called, all changes to the shared
- * document are bundled into a single event.
- */
- transact(f: () => void, undoable = true): void {
- this.ydoc.transact(f, undoable ? this : null);
- }
- /**
- * Dispose of the resources.
- */
- dispose(): void {
- this.isDisposed = true;
- this.ydoc.destroy();
- }
- /**
- * Whether the object can undo changes.
- */
- canUndo(): boolean {
- return this.undoManager.undoStack.length > 0;
- }
- /**
- * Whether the object can redo changes.
- */
- canRedo(): boolean {
- return this.undoManager.redoStack.length > 0;
- }
- /**
- * Undo an operation.
- */
- undo(): void {
- this.undoManager.undo();
- }
- /**
- * Redo an operation.
- */
- redo(): void {
- this.undoManager.redo();
- }
- /**
- * Clear the change stack.
- */
- clearUndoHistory(): void {
- this.undoManager.clear();
- }
- /**
- * The changed signal.
- */
- get changed(): ISignal<this, T> {
- return this._changed;
- }
- public isDisposed = false;
- public ydoc = new Y.Doc();
- public source = this.ydoc.getText('source');
- public undoManager = new Y.UndoManager([this.source], {
- trackedOrigins: new Set([this])
- });
- public awareness = new Awareness(this.ydoc);
- protected _changed = new Signal<this, T>(this);
- }
- export class YFile
- extends YDocument<models.FileChange>
- implements models.ISharedFile, models.ISharedText, IYText {
- constructor() {
- super();
- this.ysource.observe(this._modelObserver);
- }
- /**
- * Handle a change to the ymodel.
- */
- private _modelObserver = (event: Y.YTextEvent) => {
- const changes: models.FileChange = {};
- changes.sourceChange = event.changes.delta as any;
- this._changed.emit(changes);
- };
- public static create(): YFile {
- return new YFile();
- }
- /**
- * Gets cell's source.
- *
- * @returns Cell's source.
- */
- public getSource(): string {
- return this.ysource.toString();
- }
- /**
- * Sets cell's source.
- *
- * @param value: New source.
- */
- public setSource(value: string): void {
- this.transact(() => {
- const ytext = this.ysource;
- ytext.delete(0, ytext.length);
- ytext.insert(0, value);
- });
- }
- /**
- * Replace content from `start' to `end` with `value`.
- *
- * @param start: The start index of the range to replace (inclusive).
- *
- * @param end: The end index of the range to replace (exclusive).
- *
- * @param value: New source (optional).
- */
- public updateSource(start: number, end: number, value = ''): void {
- this.transact(() => {
- const ysource = this.ysource;
- // insert and then delete.
- // This ensures that the cursor position is adjusted after the replaced content.
- ysource.insert(start, value);
- ysource.delete(start + value.length, end - start);
- });
- }
- public ysource = this.ydoc.getText('source');
- }
- /**
- * Shared implementation of the Shared Document types.
- *
- * Shared cells can be inserted into a SharedNotebook.
- * Shared cells only start emitting events when they are connected to a SharedNotebook.
- *
- * "Standalone" cells must not be inserted into a (Shared)Notebook.
- * Standalone cells emit events immediately after they have been created, but they must not
- * be included into a (Shared)Notebook.
- */
- export class YNotebook
- extends YDocument<models.NotebookChange>
- implements models.ISharedNotebook {
- constructor() {
- super();
- this.ycells.observe(this._onYCellsChanged);
- this.cells = this.ycells.toArray().map(ycell => {
- if (!this._ycellMapping.has(ycell)) {
- this._ycellMapping.set(ycell, createCellFromType(ycell));
- }
- return this._ycellMapping.get(ycell) as YCellType;
- });
- }
- /**
- * Get a shared cell by index.
- *
- * @param index: Cell's position.
- *
- * @returns The requested shared cell.
- */
- getCell(index: number): YCellType {
- return this.cells[index];
- }
- /**
- * Insert a shared cell into a specific position.
- *
- * @param index: Cell's position.
- *
- * @param cell: Cell to insert.
- */
- insertCell(index: number, cell: YCellType): void {
- this.insertCells(index, [cell]);
- }
- /**
- * Insert a list of shared cells into a specific position.
- *
- * @param index: Position to insert the cells.
- *
- * @param cells: Array of shared cells to insert.
- */
- insertCells(index: number, cells: YCellType[]): void {
- cells.forEach(cell => {
- this._ycellMapping.set(cell.ymodel, cell);
- // cell.yawareness = this.yawareness;
- // cell.yUndoManager = this.yUndoManager;
- });
- this.transact(() => {
- this.ycells.insert(
- index,
- cells.map(cell => cell.ymodel)
- );
- });
- }
- /**
- * Move a cell.
- *
- * @param fromIndex: Index of the cell to move.
- *
- * @param toIndex: New position of the cell.
- */
- moveCell(fromIndex: number, toIndex: number): void {
- this.transact(() => {
- const fromCell: any = this.getCell(fromIndex).clone();
- this.deleteCell(fromIndex);
- this.insertCell(toIndex, fromCell);
- });
- }
- /**
- * Remove a cell.
- *
- * @param index: Index of the cell to remove.
- */
- deleteCell(index: number): void {
- this.deleteCellRange(index, index + 1);
- }
- /**
- * Remove a range of cells.
- *
- * @param from: The start index of the range to remove (inclusive).
- *
- * @param to: The end index of the range to remove (exclusive).
- */
- deleteCellRange(from: number, to: number): void {
- this.transact(() => {
- this.ycells.delete(from, to - from);
- });
- }
- /**
- * Returns the metadata associated with the notebook.
- *
- * @returns Notebook's metadata.
- */
- getMetadata(): nbformat.INotebookMetadata {
- const meta = this.ymeta.get('metadata');
- return meta ? deepCopy(meta) : { orig_nbformat: 1 };
- }
- /**
- * Sets the metadata associated with the notebook.
- *
- * @param metadata: Notebook's metadata.
- */
- setMetadata(value: nbformat.INotebookMetadata): void {
- this.ymeta.set('metadata', deepCopy(value));
- }
- /**
- * Updates the metadata associated with the notebook.
- *
- * @param value: Metadata's attribute to update.
- */
- updateMetadata(value: Partial<nbformat.INotebookMetadata>): void {
- this.ymeta.set('metadata', Object.assign({}, this.getMetadata(), value));
- }
- /**
- * Create a new YNotebook.
- */
- public static create(): models.ISharedNotebook {
- return new YNotebook();
- }
- /**
- * Dispose of the resources.
- */
- dispose(): void {
- this.ycells.unobserve(this._onYCellsChanged);
- }
- /**
- * Handle a change to the list of cells.
- */
- private _onYCellsChanged = (event: Y.YArrayEvent<Y.Map<any>>) => {
- // update the type⇔cell mapping by iterating through the addded/removed types
- event.changes.added.forEach(item => {
- const type = (item.content as Y.ContentType).type as Y.Map<any>;
- if (!this._ycellMapping.has(type)) {
- this._ycellMapping.set(type, createCellFromType(type));
- }
- const cell = this._ycellMapping.get(type) as any;
- cell._notebook = this;
- cell._undoManager = this.undoManager;
- });
- event.changes.deleted.forEach(item => {
- const type = (item.content as Y.ContentType).type as Y.Map<any>;
- const model = this._ycellMapping.get(type);
- if (model) {
- model.dispose();
- this._ycellMapping.delete(type);
- }
- });
- let index = 0;
- // this reflects the event.changes.delta, but replaces the content of delta.insert with ycells
- const cellsChange: Delta<models.ISharedCell[]> = [];
- event.changes.delta.forEach((d: any) => {
- if (d.insert != null) {
- const insertedCells = d.insert.map((ycell: Y.Map<any>) =>
- this._ycellMapping.get(ycell)
- );
- cellsChange.push({ insert: insertedCells });
- this.cells.splice(index, 0, ...insertedCells);
- index += d.insert.length;
- } else if (d.delete != null) {
- cellsChange.push(d);
- this.cells.splice(index, d.delete);
- } else if (d.retain != null) {
- cellsChange.push(d);
- index += d.retain;
- }
- });
- this._changed.emit({
- cellsChange: cellsChange
- });
- };
- public ycells: Y.Array<Y.Map<any>> = this.ydoc.getArray('cells');
- public ymeta: Y.Map<any> = this.ydoc.getMap('meta');
- public ymodel: Y.Map<any> = this.ydoc.getMap('model');
- public undoManager = new Y.UndoManager([this.ycells], {
- trackedOrigins: new Set([this])
- });
- private _ycellMapping: Map<Y.Map<any>, YCellType> = new Map();
- public nbformat_minor: number = nbformat.MINOR_VERSION;
- public nbformat: number = nbformat.MAJOR_VERSION;
- public cells: YCellType[];
- }
- /**
- * Create a new shared cell given the type.
- */
- export const createCellFromType = (type: Y.Map<any>): YCellType => {
- switch (type.get('cell_type')) {
- case 'code':
- return new YCodeCell(type);
- case 'markdown':
- return new YMarkdownCell(type);
- case 'raw':
- return new YRawCell(type);
- default:
- throw new Error('Found unknown cell type');
- }
- };
- /**
- * Create a new standalone cell given the type.
- */
- export const createStandaloneCell = (
- cellType: 'raw' | 'code' | 'markdown',
- id?: string
- ): YCellType => {
- switch (cellType) {
- case 'markdown':
- return YMarkdownCell.createStandalone(id);
- case 'code':
- return YCodeCell.createStandalone(id);
- default:
- // raw
- return YRawCell.createStandalone(id);
- }
- };
- export class YBaseCell<Metadata extends models.ISharedBaseCellMetadata>
- implements models.ISharedBaseCell<Metadata>, IYText {
- constructor(ymodel: Y.Map<any>) {
- this.ymodel = ymodel;
- const ysource = ymodel.get('source');
- this._prevSourceLength = ysource ? ysource.length : 0;
- this.ymodel.observeDeep(this._modelObserver);
- }
- get ysource(): Y.Text {
- return this.ymodel.get('source');
- }
- get awareness(): Awareness | null {
- return this.notebook?.awareness || null;
- }
- /**
- * Perform a transaction. While the function f is called, all changes to the shared
- * document are bundled into a single event.
- */
- transact(f: () => void, undoable = true): void {
- this.notebook && undoable
- ? this.notebook.transact(f)
- : this.ymodel.doc!.transact(f, this);
- }
- /**
- * The notebook that this cell belongs to.
- */
- get undoManager(): Y.UndoManager | null {
- return this.notebook ? this.notebook.undoManager : this._undoManager;
- }
- /**
- * Undo an operation.
- */
- undo(): void {
- this.undoManager?.undo();
- }
- /**
- * Redo an operation.
- */
- redo(): void {
- this.undoManager?.redo();
- }
- /**
- * Whether the object can undo changes.
- */
- canUndo(): boolean {
- return !!this.undoManager && this.undoManager.undoStack.length > 0;
- }
- /**
- * Whether the object can redo changes.
- */
- canRedo(): boolean {
- return !!this.undoManager && this.undoManager.redoStack.length > 0;
- }
- /**
- * Clear the change stack.
- */
- clearUndoHistory(): void {
- this.undoManager?.clear();
- }
- /**
- * The notebook that this cell belongs to.
- */
- get notebook(): YNotebook | null {
- return this._notebook;
- }
- /**
- * The notebook that this cell belongs to.
- */
- protected _notebook: YNotebook | null = null;
- /**
- * Whether the cell is standalone or not.
- *
- * If the cell is standalone. It cannot be
- * inserted into a YNotebook because the Yjs model is already
- * attached to an anonymous Y.Doc instance.
- */
- isStandalone = false;
- /**
- * Create a new YRawCell that can be inserted into a YNotebook
- */
- public static create(id = UUID.uuid4()): YBaseCell<any> {
- const ymodel = new Y.Map();
- const ysource = new Y.Text();
- ymodel.set('source', ysource);
- ymodel.set('metadata', {});
- ymodel.set('cell_type', this.prototype.cell_type);
- ymodel.set('id', id);
- return new this(ymodel);
- }
- /**
- * Create a new YRawCell that works standalone. It cannot be
- * inserted into a YNotebook because the Yjs model is already
- * attached to an anonymous Y.Doc instance.
- */
- public static createStandalone(id?: string): YBaseCell<any> {
- const cell = this.create(id);
- cell.isStandalone = true;
- new Y.Doc().getArray().insert(0, [cell.ymodel]);
- cell._undoManager = new Y.UndoManager([cell.ymodel], {
- trackedOrigins: new Set([cell])
- });
- return cell;
- }
- /**
- * Clone the cell.
- *
- * @todo clone should only be available in the specific implementations i.e. ISharedCodeCell
- */
- public clone(): YBaseCell<any> {
- const ymodel = new Y.Map();
- const ysource = new Y.Text(this.getSource());
- ymodel.set('source', ysource);
- ymodel.set('metadata', this.getMetadata());
- ymodel.set('cell_type', this.cell_type);
- ymodel.set('id', this.getId());
- const Self: any = this.constructor;
- return new Self(ymodel);
- }
- /**
- * Handle a change to the ymodel.
- */
- private _modelObserver = (events: Y.YEvent[]) => {
- const changes: models.CellChange<Metadata> = {};
- const sourceEvent = events.find(
- event => event.target === this.ymodel.get('source')
- );
- if (sourceEvent) {
- changes.sourceChange = sourceEvent.changes.delta as any;
- }
- const outputEvent = events.find(
- event => event.target === this.ymodel.get('outputs')
- );
- if (outputEvent) {
- changes.outputsChange = outputEvent.changes.delta as any;
- }
- const modelEvent = events.find(event => event.target === this.ymodel) as
- | undefined
- | Y.YMapEvent<any>;
- if (modelEvent && modelEvent.keysChanged.has('metadata')) {
- const change = modelEvent.changes.keys.get('metadata');
- changes.metadataChange = {
- oldValue: change?.oldValue ? change!.oldValue : undefined,
- newValue: this.getMetadata()
- };
- }
- if (modelEvent && modelEvent.keysChanged.has('execution_count')) {
- const change = modelEvent.changes.keys.get('execution_count');
- changes.executionCountChange = {
- oldValue: change!.oldValue,
- newValue: this.ymodel.get('execution_count')
- };
- }
- // The model allows us to replace the complete source with a new string. We express this in the Delta format
- // as a replace of the complete string.
- const ysource = this.ymodel.get('source');
- if (modelEvent && modelEvent.keysChanged.has('source')) {
- changes.sourceChange = [
- { delete: this._prevSourceLength },
- { insert: ysource.toString() }
- ];
- }
- this._prevSourceLength = ysource.length;
- this._changed.emit(changes);
- };
- /**
- * The changed signal.
- */
- get changed(): ISignal<this, models.CellChange<Metadata>> {
- return this._changed;
- }
- /**
- * Dispose of the resources.
- */
- dispose(): void {
- this.ymodel.unobserveDeep(this._modelObserver);
- }
- /**
- * Gets the cell attachments.
- *
- * @returns The cell attachments.
- */
- public getAttachments(): nbformat.IAttachments | undefined {
- return this.ymodel.get('attachments');
- }
- /**
- * Sets the cell attachments
- *
- * @param attchments: The cell attachments.
- */
- public setAttachments(value: nbformat.IAttachments | undefined): void {
- this.transact(() => {
- if (value == null) {
- this.ymodel.set('attachments', value);
- } else {
- this.ymodel.delete('attachments');
- }
- });
- }
- /**
- * Get cell id.
- *
- * @returns Cell id
- */
- public getId(): string {
- return this.ymodel.get('id');
- }
- /**
- * Gets cell's source.
- *
- * @returns Cell's source.
- */
- public getSource(): string {
- return this.ymodel.get('source').toString();
- }
- /**
- * Sets cell's source.
- *
- * @param value: New source.
- */
- public setSource(value: string): void {
- const ytext = this.ymodel.get('source');
- this.transact(() => {
- ytext.delete(0, ytext.length);
- ytext.insert(0, value);
- });
- // @todo Do we need proper replace semantic? This leads to issues in editor bindings because they don't switch source.
- // this.ymodel.set('source', new Y.Text(value));
- }
- /**
- * Replace content from `start' to `end` with `value`.
- *
- * @param start: The start index of the range to replace (inclusive).
- *
- * @param end: The end index of the range to replace (exclusive).
- *
- * @param value: New source (optional).
- */
- public updateSource(start: number, end: number, value = ''): void {
- this.transact(() => {
- const ysource = this.ysource;
- // insert and then delete.
- // This ensures that the cursor position is adjusted after the replaced content.
- ysource.insert(start, value);
- ysource.delete(start + value.length, end - start);
- });
- }
- /**
- * The type of the cell.
- */
- get cell_type(): any {
- throw new Error('A YBaseCell must not be constructed');
- }
- /**
- * Returns the metadata associated with the notebook.
- *
- * @returns Notebook's metadata.
- */
- getMetadata(): Partial<Metadata> {
- return deepCopy(this.ymodel.get('metadata'));
- }
- /**
- * Sets the metadata associated with the notebook.
- *
- * @param metadata: Notebook's metadata.
- */
- setMetadata(value: Partial<Metadata>): void {
- this.transact(() => {
- this.ymodel.set('metadata', deepCopy(value));
- });
- }
- /**
- * Serialize the model to JSON.
- */
- toJSON(): nbformat.IBaseCell {
- return {
- id: this.getId(),
- cell_type: this.cell_type,
- source: this.getSource(),
- metadata: this.getMetadata()
- };
- }
- public isDisposed = false;
- public ymodel: Y.Map<any>;
- private _undoManager: Y.UndoManager | null = null;
- private _changed = new Signal<this, models.CellChange<Metadata>>(this);
- private _prevSourceLength: number;
- }
- export class YCodeCell
- extends YBaseCell<models.ISharedBaseCellMetadata>
- implements models.ISharedCodeCell {
- /**
- * The type of the cell.
- */
- get cell_type(): 'code' {
- return 'code';
- }
- /**
- * The code cell's prompt number. Will be null if the cell has not been run.
- */
- get execution_count(): number | null {
- return this.ymodel.get('execution_count');
- }
- /**
- * The code cell's prompt number. Will be null if the cell has not been run.
- */
- set execution_count(count: number | null) {
- this.transact(() => {
- this.ymodel.set('execution_count', count);
- });
- }
- /**
- * Execution, display, or stream outputs.
- */
- getOutputs(): Array<nbformat.IOutput> {
- return deepCopy(this.ymodel.get('outputs').toArray());
- }
- /**
- * Replace all outputs.
- */
- setOutputs(outputs: Array<nbformat.IOutput>): void {
- const youtputs = this.ymodel.get('outputs') as Y.Array<nbformat.IOutput>;
- this.transact(() => {
- youtputs.delete(0, youtputs.length);
- youtputs.insert(0, outputs);
- });
- }
- /**
- * Replace content from `start' to `end` with `outputs`.
- *
- * @param start: The start index of the range to replace (inclusive).
- *
- * @param end: The end index of the range to replace (exclusive).
- *
- * @param outputs: New outputs (optional).
- */
- updateOutputs(
- start: number,
- end: number,
- outputs: Array<nbformat.IOutput> = []
- ): void {
- const youtputs = this.ymodel.get('outputs') as Y.Array<nbformat.IOutput>;
- const fin = end < youtputs.length ? end - start : youtputs.length - start;
- this.transact(() => {
- youtputs.delete(start, fin);
- youtputs.insert(start, outputs);
- });
- }
- /**
- * Create a new YCodeCell that can be inserted into a YNotebook
- */
- public static create(id?: string): YCodeCell {
- const cell = super.create(id);
- cell.ymodel.set('execution_count', 0); // for some default value
- cell.ymodel.set('outputs', new Y.Array<nbformat.IOutput>());
- return cell as any;
- }
- /**
- * Create a new YCodeCell that works standalone. It cannot be
- * inserted into a YNotebook because the Yjs model is already
- * attached to an anonymous Y.Doc instance.
- */
- public static createStandalone(id?: string): YCodeCell {
- const cell = super.createStandalone(id);
- cell.ymodel.set('execution_count', null); // for some default value
- cell.ymodel.set('outputs', new Y.Array<nbformat.IOutput>());
- return cell as any;
- }
- /**
- * Create a new YCodeCell that can be inserted into a YNotebook
- *
- * @todo clone should only be available in the specific implementations i.e. ISharedCodeCell
- */
- public clone(): YCodeCell {
- const cell = super.clone();
- const youtputs = new Y.Array<nbformat.IOutput>();
- youtputs.insert(0, this.getOutputs());
- cell.ymodel.set('execution_count', this.execution_count); // for some default value
- cell.ymodel.set('outputs', youtputs);
- return cell as any;
- }
- /**
- * Serialize the model to JSON.
- */
- toJSON(): nbformat.ICodeCell {
- return {
- id: this.getId(),
- cell_type: 'code',
- source: this.getSource(),
- metadata: this.getMetadata(),
- outputs: this.getOutputs(),
- execution_count: this.execution_count
- };
- }
- }
- export class YRawCell
- extends YBaseCell<models.ISharedBaseCellMetadata>
- implements models.ISharedRawCell {
- /**
- * Create a new YRawCell that can be inserted into a YNotebook
- */
- public static create(id?: string): YRawCell {
- return super.create(id) as any;
- }
- /**
- * Create a new YRawCell that works standalone. It cannot be
- * inserted into a YNotebook because the Yjs model is already
- * attached to an anonymous Y.Doc instance.
- */
- public static createStandalone(id?: string): YRawCell {
- return super.createStandalone(id) as any;
- }
- /**
- * String identifying the type of cell.
- */
- get cell_type(): 'raw' {
- return 'raw';
- }
- /**
- * Serialize the model to JSON.
- */
- toJSON(): nbformat.IRawCell {
- return {
- id: this.getId(),
- cell_type: 'raw',
- source: this.getSource(),
- metadata: this.getMetadata(),
- attachments: this.getAttachments()
- };
- }
- }
- export class YMarkdownCell
- extends YBaseCell<models.ISharedBaseCellMetadata>
- implements models.ISharedMarkdownCell {
- /**
- * Create a new YMarkdownCell that can be inserted into a YNotebook
- */
- public static create(id?: string): YMarkdownCell {
- return super.create(id) as any;
- }
- /**
- * Create a new YMarkdownCell that works standalone. It cannot be
- * inserted into a YNotebook because the Yjs model is already
- * attached to an anonymous Y.Doc instance.
- */
- public static createStandalone(id?: string): YMarkdownCell {
- return super.createStandalone(id) as any;
- }
- /**
- * String identifying the type of cell.
- */
- get cell_type(): 'markdown' {
- return 'markdown';
- }
- /**
- * Serialize the model to JSON.
- */
- toJSON(): nbformat.IMarkdownCell {
- return {
- id: this.getId(),
- cell_type: 'markdown',
- source: this.getSource(),
- metadata: this.getMetadata(),
- attachments: this.getAttachments()
- };
- }
- }
- export default YNotebook;
|