|
@@ -141,6 +141,10 @@ class OutputAreaWidget extends Widget {
|
|
}
|
|
}
|
|
let oldValue = this._model;
|
|
let oldValue = this._model;
|
|
this._model = newValue;
|
|
this._model = newValue;
|
|
|
|
+ if (oldValue) {
|
|
|
|
+ oldValue.changed.disconnect(this._onModelChange, this);
|
|
|
|
+ }
|
|
|
|
+ newValue.changed.connect(this._onModelChange, this);
|
|
this.onModelChanged(oldValue, newValue);
|
|
this.onModelChanged(oldValue, newValue);
|
|
this.modelChanged.emit(void 0);
|
|
this.modelChanged.emit(void 0);
|
|
}
|
|
}
|
|
@@ -176,7 +180,7 @@ class OutputAreaWidget extends Widget {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
this._trusted = value;
|
|
this._trusted = value;
|
|
- this.onTrustedChanged(value);
|
|
|
|
|
|
+ this.onTrustChanged(value);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -269,6 +273,9 @@ class OutputAreaWidget extends Widget {
|
|
|
|
|
|
/**
|
|
/**
|
|
* Handle a change to the model.
|
|
* Handle a change to the model.
|
|
|
|
+ *
|
|
|
|
+ * The default implementation is to remove all of the old widgets
|
|
|
|
+ * and add new widgets for the new outputs.
|
|
*/
|
|
*/
|
|
protected onModelChanged(oldValue: OutputAreaModel, newValue: OutputAreaModel): void {
|
|
protected onModelChanged(oldValue: OutputAreaModel, newValue: OutputAreaModel): void {
|
|
let layout = this.layout as PanelLayout;
|
|
let layout = this.layout as PanelLayout;
|
|
@@ -279,54 +286,40 @@ class OutputAreaWidget extends Widget {
|
|
if (!newValue) {
|
|
if (!newValue) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- newValue.changed.connect(this.onModelChange, this);
|
|
|
|
|
|
+ let renderer = this.renderer;
|
|
|
|
+ let rendermime = this.rendermime;
|
|
|
|
+ let trusted = this.trusted;
|
|
for (let i = 0; i < newValue.length; i++) {
|
|
for (let i = 0; i < newValue.length; i++) {
|
|
- let widget = this.createOutput(newValue.get(i));
|
|
|
|
|
|
+ let output = newValue.get(i);
|
|
|
|
+ let widget = renderer.createOutput(output, rendermime, trusted);
|
|
layout.addChild(widget);
|
|
layout.addChild(widget);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Handle a change to the trusted state.
|
|
|
|
- */
|
|
|
|
- protected onTrustedChanged(value: boolean): void {
|
|
|
|
- // Re-render only if necessary.
|
|
|
|
- let model = this.model;
|
|
|
|
- if (!model) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- let layout = this.layout as PanelLayout;
|
|
|
|
- for (let i = 0; i < layout.childCount(); i++) {
|
|
|
|
- layout.childAt(0).dispose();
|
|
|
|
- }
|
|
|
|
- for (let i = 0; i < model.length; i++) {
|
|
|
|
- layout.addChild(this.createOutput(model.get(i)));
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Create an output widget for an output model.
|
|
|
|
|
|
+ * Handle a change in trust.
|
|
|
|
+ *
|
|
|
|
+ * The default implementation is to call `onModelChanged`.
|
|
*/
|
|
*/
|
|
- protected createOutput(output: nbformat.IOutput): Widget {
|
|
|
|
- let renderer = this.renderer;
|
|
|
|
- let bundle = renderer.getBundle(output);
|
|
|
|
- let map = OutputAreaWidget.convertBundle(bundle);
|
|
|
|
- if (!this.trusted) {
|
|
|
|
- renderer.sanitize(map);
|
|
|
|
- }
|
|
|
|
- return renderer.createOutput(output, map, this.rendermime);
|
|
|
|
|
|
+ protected onTrustChanged(value: boolean): void {
|
|
|
|
+ this.onModelChanged(this.model, this.model);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* Follow changes to the model.
|
|
* Follow changes to the model.
|
|
*/
|
|
*/
|
|
- protected onModelChange(sender: OutputAreaModel, args: IListChangedArgs<nbformat.IOutput>) {
|
|
|
|
|
|
+ private _onModelChange(sender: OutputAreaModel, args: IListChangedArgs<nbformat.IOutput>) {
|
|
let layout = this.layout as PanelLayout;
|
|
let layout = this.layout as PanelLayout;
|
|
|
|
+ let value: nbformat.IOutput;
|
|
|
|
+ let renderer = this.renderer;
|
|
|
|
+ let rendermime = this.rendermime;
|
|
|
|
+ let trusted = this.trusted;
|
|
let widget: Widget;
|
|
let widget: Widget;
|
|
switch (args.type) {
|
|
switch (args.type) {
|
|
case ListChangeType.Add:
|
|
case ListChangeType.Add:
|
|
- let value = args.newValue as nbformat.IOutput;
|
|
|
|
- layout.insertChild(args.newIndex, this.createOutput(value));
|
|
|
|
|
|
+ value = args.newValue as nbformat.IOutput;
|
|
|
|
+ widget = renderer.createOutput(value, rendermime, trusted);
|
|
|
|
+ layout.addChild(widget);
|
|
break;
|
|
break;
|
|
case ListChangeType.Replace:
|
|
case ListChangeType.Replace:
|
|
// Only "clear" is supported by the model.
|
|
// Only "clear" is supported by the model.
|
|
@@ -336,9 +329,10 @@ class OutputAreaWidget extends Widget {
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case ListChangeType.Set:
|
|
case ListChangeType.Set:
|
|
- layout.childAt(args.newIndex).parent = null;
|
|
|
|
- widget = this.createOutput(args.newValue as nbformat.IOutput);
|
|
|
|
- layout.insertChild(args.newIndex, widget);
|
|
|
|
|
|
+ layout.childAt(args.oldIndex).parent = null;
|
|
|
|
+ value = args.newValue as nbformat.IOutput;
|
|
|
|
+ widget = renderer.createOutput(value, rendermime, trusted);
|
|
|
|
+ layout.addChild(widget);
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
break;
|
|
break;
|
|
@@ -384,57 +378,82 @@ namespace OutputAreaWidget {
|
|
export
|
|
export
|
|
interface IRenderer {
|
|
interface IRenderer {
|
|
/**
|
|
/**
|
|
- * Get the mime bundle for an output.
|
|
|
|
|
|
+ * Create an output widget.
|
|
*
|
|
*
|
|
- * @params output - A kernel output message payload.
|
|
|
|
|
|
+ * @param output - The kernel output message payload.
|
|
*
|
|
*
|
|
- * @returns - A mime bundle for the payload.
|
|
|
|
- */
|
|
|
|
- getBundle(output: nbformat.IOutput): nbformat.MimeBundle;
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Sanitize a mime map.
|
|
|
|
|
|
+ * @param rendermime - The rendermime instance.
|
|
*
|
|
*
|
|
- * @params map - The map to sanitize.
|
|
|
|
|
|
+ * @param trusted - Whether the output is trusted.
|
|
|
|
+ *
|
|
|
|
+ * @returns A widget containing the rendered data.
|
|
*/
|
|
*/
|
|
- sanitize(map: MimeMap<string>): void;
|
|
|
|
|
|
+ createOutput(output: nbformat.IOutput, rendermime: RenderMime<Widget>, trusted?: boolean): Widget;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * The default implementation of `IRenderer`.
|
|
|
|
+ */
|
|
|
|
+ export
|
|
|
|
+ class Renderer implements IRenderer {
|
|
/**
|
|
/**
|
|
* Create an output widget.
|
|
* Create an output widget.
|
|
*
|
|
*
|
|
- * @param output - The original kernel output message payload.
|
|
|
|
- *
|
|
|
|
- * @param data - The processed data from the output.
|
|
|
|
|
|
+ * @param output - The kernel output message payload.
|
|
*
|
|
*
|
|
* @param rendermime - The rendermime instance.
|
|
* @param rendermime - The rendermime instance.
|
|
*
|
|
*
|
|
|
|
+ * @param trusted - Whether the output is trusted.
|
|
|
|
+ *
|
|
* @returns A widget containing the rendered data.
|
|
* @returns A widget containing the rendered data.
|
|
*/
|
|
*/
|
|
- createOutput(output: nbformat.IOutput, data: MimeMap<string>, rendermime: RenderMime<Widget>): Widget;
|
|
|
|
- }
|
|
|
|
|
|
+ createOutput(output: nbformat.IOutput, rendermime: RenderMime<Widget>, trusted = false): Widget {
|
|
|
|
+ let bundle = this.getBundle(output);
|
|
|
|
+ let data = this.convertBundle(bundle);
|
|
|
|
+ if (!trusted) {
|
|
|
|
+ this.sanitize(data);
|
|
|
|
+ }
|
|
|
|
+ let widget = new Panel();
|
|
|
|
+ switch (output.output_type) {
|
|
|
|
+ case 'execute_result':
|
|
|
|
+ widget.addClass(EXECUTE_CLASS);
|
|
|
|
+ let prompt = new Widget();
|
|
|
|
+ prompt.addClass(PROMPT_CLASS);
|
|
|
|
+ let count = (output as nbformat.IExecuteResult).execution_count;
|
|
|
|
+ prompt.node.textContent = `Out[${count === null ? ' ' : count}]:`;
|
|
|
|
+ widget.addChild(prompt);
|
|
|
|
+ break;
|
|
|
|
+ case 'display_data':
|
|
|
|
+ widget.addClass(DISPLAY_CLASS);
|
|
|
|
+ break;
|
|
|
|
+ case 'stream':
|
|
|
|
+ if ((output as nbformat.IStream).name === 'stdout') {
|
|
|
|
+ widget.addClass(STDOUT_CLASS);
|
|
|
|
+ } else {
|
|
|
|
+ widget.addClass(STDERR_CLASS);
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ case 'error':
|
|
|
|
+ widget.addClass(ERROR_CLASS);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ console.error(`Unrecognized output type: ${output.output_type}`);
|
|
|
|
+ data = {};
|
|
|
|
+ }
|
|
|
|
|
|
- /**
|
|
|
|
- * Convert a mime bundle to a mime map.
|
|
|
|
- */
|
|
|
|
- export
|
|
|
|
- function convertBundle(bundle: nbformat.MimeBundle): MimeMap<string> {
|
|
|
|
- let map: MimeMap<string> = Object.create(null);
|
|
|
|
- for (let mimeType in bundle) {
|
|
|
|
- let value = bundle[mimeType];
|
|
|
|
- if (Array.isArray(value)) {
|
|
|
|
- map[mimeType] = (value as string[]).join('\n');
|
|
|
|
- } else {
|
|
|
|
- map[mimeType] = value as string;
|
|
|
|
|
|
+ if (data) {
|
|
|
|
+ let child = rendermime.render(data);
|
|
|
|
+ if (child) {
|
|
|
|
+ child.addClass(RESULT_CLASS);
|
|
|
|
+ widget.addChild(child);
|
|
|
|
+ } else {
|
|
|
|
+ console.log('Did not find renderer for output mimebundle.');
|
|
|
|
+ console.log(data);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+ return widget;
|
|
}
|
|
}
|
|
- return map;
|
|
|
|
- }
|
|
|
|
|
|
|
|
- /**
|
|
|
|
- * The default implementation of `IRenderer`.
|
|
|
|
- */
|
|
|
|
- export
|
|
|
|
- class Renderer implements IRenderer {
|
|
|
|
/**
|
|
/**
|
|
* Get the mime bundle for an output.
|
|
* Get the mime bundle for an output.
|
|
*
|
|
*
|
|
@@ -466,10 +485,28 @@ namespace OutputAreaWidget {
|
|
return bundle;
|
|
return bundle;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Convert a mime bundle to a mime map.
|
|
|
|
+ */
|
|
|
|
+ convertBundle(bundle: nbformat.MimeBundle): MimeMap<string> {
|
|
|
|
+ let map: MimeMap<string> = Object.create(null);
|
|
|
|
+ for (let mimeType in bundle) {
|
|
|
|
+ let value = bundle[mimeType];
|
|
|
|
+ if (Array.isArray(value)) {
|
|
|
|
+ map[mimeType] = (value as string[]).join('\n');
|
|
|
|
+ } else {
|
|
|
|
+ map[mimeType] = value as string;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return map;
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Sanitize a mime map.
|
|
* Sanitize a mime map.
|
|
*
|
|
*
|
|
* @params map - The map to sanitize.
|
|
* @params map - The map to sanitize.
|
|
|
|
+ *
|
|
|
|
+ * @returns Whether the
|
|
*/
|
|
*/
|
|
sanitize(map: MimeMap<string>): void {
|
|
sanitize(map: MimeMap<string>): void {
|
|
let keys = Object.keys(map);
|
|
let keys = Object.keys(map);
|
|
@@ -491,59 +528,6 @@ namespace OutputAreaWidget {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Create an output widget.
|
|
|
|
- *
|
|
|
|
- * @param output - The original kernel output message payload.
|
|
|
|
- *
|
|
|
|
- * @param data - The processed data from the output.
|
|
|
|
- *
|
|
|
|
- * @param rendermime - The rendermime instance.
|
|
|
|
- *
|
|
|
|
- * @returns A widget containing the rendered data.
|
|
|
|
- */
|
|
|
|
- createOutput(output: nbformat.IOutput, data: MimeMap<string>, rendermime: RenderMime<Widget>): Widget {
|
|
|
|
- let widget = new Panel();
|
|
|
|
- switch (output.output_type) {
|
|
|
|
- case 'execute_result':
|
|
|
|
- widget.addClass(EXECUTE_CLASS);
|
|
|
|
- let prompt = new Widget();
|
|
|
|
- prompt.addClass(PROMPT_CLASS);
|
|
|
|
- let count = (output as nbformat.IExecuteResult).execution_count;
|
|
|
|
- prompt.node.textContent = `Out[${count === null ? ' ' : count}]:`;
|
|
|
|
- widget.addChild(prompt);
|
|
|
|
- break;
|
|
|
|
- case 'display_data':
|
|
|
|
- widget.addClass(DISPLAY_CLASS);
|
|
|
|
- break;
|
|
|
|
- case 'stream':
|
|
|
|
- if ((output as nbformat.IStream).name === 'stdout') {
|
|
|
|
- widget.addClass(STDOUT_CLASS);
|
|
|
|
- } else {
|
|
|
|
- widget.addClass(STDERR_CLASS);
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- case 'error':
|
|
|
|
- widget.addClass(ERROR_CLASS);
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- console.error(`Unrecognized output type: ${output.output_type}`);
|
|
|
|
- data = {};
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (data) {
|
|
|
|
- let child = rendermime.render(data);
|
|
|
|
- if (child) {
|
|
|
|
- child.addClass(RESULT_CLASS);
|
|
|
|
- widget.addChild(child);
|
|
|
|
- } else {
|
|
|
|
- console.log('Did not find renderer for output mimebundle.');
|
|
|
|
- console.log(data);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return widget;
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|