mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-22 01:25:38 -05:00
Output view changes (#3146)
* 1133: Notebook file registration changes * File registration stuff * Yarn files * Outputview Changes * Misc changes * Changes to code component name space * Output view changes * notebook output view changes * Latest changes * Output view changes * Code review changes on output view * CSS file and misc changes
This commit is contained in:
@@ -8,8 +8,6 @@ import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetecto
|
||||
|
||||
import { CommonServiceInterface } from 'sql/services/common/commonServiceInterface.service';
|
||||
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
|
||||
import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
|
||||
import { QueryTextEditor } from 'sql/parts/modelComponents/queryTextEditor';
|
||||
|
||||
import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<div class="notebook-code" style="flex: 0 0 auto;">
|
||||
<code-component [cellModel]="cellModel"></code-component>
|
||||
</div>
|
||||
<div #output class="notebook-output" style="flex: 0 0 auto;">
|
||||
Place Holder for output area
|
||||
<div class="notebook-output" style="flex: 0 0 auto;">
|
||||
<output-area-component *ngIf="cellModel.outputs && cellModel.outputs.length > 0" [cellModel]="cellModel">
|
||||
</output-area-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -21,10 +21,8 @@ export const CODE_SELECTOR: string = 'code-cell-component';
|
||||
templateUrl: decodeURI(require.toUrl('./codeCell.component.html'))
|
||||
})
|
||||
export class CodeCellComponent extends CellView implements OnInit {
|
||||
@ViewChild('output', { read: ElementRef }) private output: ElementRef;
|
||||
@Input() cellModel: ICellModel;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService
|
||||
) {
|
||||
@@ -42,7 +40,5 @@ export class CodeCellComponent extends CellView implements OnInit {
|
||||
}
|
||||
|
||||
private updateTheme(theme: IColorTheme): void {
|
||||
let outputElement = <HTMLElement>this.output.nativeElement;
|
||||
outputElement.style.borderTopColor = theme.getColor(themeColors.SIDE_BAR_BACKGROUND, true).toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,3 +13,5 @@ export abstract class CellView extends AngularDisposable implements OnDestroy {
|
||||
|
||||
public abstract layout(): void;
|
||||
}
|
||||
|
||||
|
||||
|
||||
11
src/sql/parts/notebook/cellViews/output.component.html
Normal file
11
src/sql/parts/notebook/cellViews/output.component.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!--
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column">
|
||||
<div style="flex: 0 0 auto; user-select: initial;">
|
||||
<div #output ></div>
|
||||
</div>
|
||||
</div>
|
||||
77
src/sql/parts/notebook/cellViews/output.component.ts
Normal file
77
src/sql/parts/notebook/cellViews/output.component.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import 'vs/css!./code';
|
||||
|
||||
import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, Output, EventEmitter } from '@angular/core';
|
||||
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||
import { nb } from 'sqlops';
|
||||
import { INotebookService } from 'sql/services/notebook/notebookService';
|
||||
import { MimeModel } from 'sql/parts/notebook/outputs/common/mimemodel';
|
||||
import * as outputProcessor from '../outputs/common/outputProcessor';
|
||||
import { RenderMimeRegistry } from 'sql/parts/notebook/outputs/registry';
|
||||
import 'vs/css!sql/parts/notebook/outputs/style/index';
|
||||
|
||||
export const OUTPUT_SELECTOR: string = 'output-component';
|
||||
|
||||
@Component({
|
||||
selector: OUTPUT_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('./output.component.html'))
|
||||
})
|
||||
export class OutputComponent extends AngularDisposable implements OnInit {
|
||||
@ViewChild('output', { read: ElementRef }) private outputElement: ElementRef;
|
||||
@Input() cellOutput: nb.ICellOutput;
|
||||
private readonly _minimumHeight = 30;
|
||||
registry: RenderMimeRegistry;
|
||||
trusted: boolean = false;
|
||||
|
||||
|
||||
constructor(
|
||||
@Inject(INotebookService) private _notebookService: INotebookService
|
||||
) {
|
||||
super();
|
||||
this.registry = _notebookService.getMimeRegistry();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
let node = this.outputElement.nativeElement;
|
||||
let output = this.cellOutput;
|
||||
let options = outputProcessor.getBundleOptions({ value: output, trusted: this.trusted });
|
||||
// TODO handle safe/unsafe mapping
|
||||
this.createRenderedMimetype(options, node);
|
||||
}
|
||||
|
||||
public layout(): void {
|
||||
}
|
||||
|
||||
protected createRenderedMimetype(options: MimeModel.IOptions, node: HTMLElement): void {
|
||||
let mimeType = this.registry.preferredMimeType(
|
||||
options.data,
|
||||
options.trusted ? 'any' : 'ensure'
|
||||
);
|
||||
if (mimeType) {
|
||||
let output = this.registry.createRenderer(mimeType);
|
||||
output.node = node;
|
||||
let model = new MimeModel(options);
|
||||
output.renderModel(model).catch(error => {
|
||||
// Manually append error message to output
|
||||
output.node.innerHTML = `<pre>Javascript Error: ${error.message}</pre>`;
|
||||
// Remove mime-type-specific CSS classes
|
||||
output.node.className = 'p-Widget jp-RenderedText';
|
||||
output.node.setAttribute(
|
||||
'data-mime-type',
|
||||
'application/vnd.jupyter.stderr'
|
||||
);
|
||||
});
|
||||
//this.setState({ node: node });
|
||||
} else {
|
||||
// TODO Localize
|
||||
node.innerHTML =
|
||||
`No ${options.trusted ? '' : '(safe) '}renderer could be ` +
|
||||
'found for output. It has the following MIME types: ' +
|
||||
Object.keys(options.data).join(', ');
|
||||
//this.setState({ node: node });
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/sql/parts/notebook/cellViews/outputArea.component.html
Normal file
12
src/sql/parts/notebook/cellViews/outputArea.component.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!--
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
-->
|
||||
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column">
|
||||
<div class="notebook-output" style="flex: 0 0 auto;">
|
||||
<output-component *ngFor="let output of cellModel.outputs" [cellOutput]="output">
|
||||
</output-component>
|
||||
</div>
|
||||
</div>
|
||||
30
src/sql/parts/notebook/cellViews/outputArea.component.ts
Normal file
30
src/sql/parts/notebook/cellViews/outputArea.component.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import 'vs/css!./code';
|
||||
import { OnInit, Component, Input, Inject, forwardRef, ElementRef, ChangeDetectorRef, OnDestroy, ViewChild, Output, EventEmitter } from '@angular/core';
|
||||
import { AngularDisposable } from 'sql/base/common/lifecycle';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { ICellModel } from 'sql/parts/notebook/models/modelInterfaces';
|
||||
|
||||
export const OUTPUT_AREA_SELECTOR: string = 'output-area-component';
|
||||
|
||||
@Component({
|
||||
selector: OUTPUT_AREA_SELECTOR,
|
||||
templateUrl: decodeURI(require.toUrl('./outputArea.component.html'))
|
||||
})
|
||||
export class OutputAreaComponent extends AngularDisposable implements OnInit {
|
||||
@Input() cellModel: ICellModel;
|
||||
|
||||
private readonly _minimumHeight = 30;
|
||||
|
||||
constructor(
|
||||
@Inject(IModeService) private _modeService: IModeService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
ngOnInit(): void {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -338,6 +338,7 @@ export interface ICellModel {
|
||||
cellType: CellType;
|
||||
trustedMode: boolean;
|
||||
active: boolean;
|
||||
readonly outputs: ReadonlyArray<nb.ICellOutput>;
|
||||
equals(cellModel: ICellModel): boolean;
|
||||
toJSON(): nb.ICell;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { CodeComponent } from 'sql/parts/notebook/cellViews/code.component';
|
||||
import { CodeCellComponent } from 'sql/parts/notebook/cellViews/codeCell.component';
|
||||
import { TextCellComponent } from 'sql/parts/notebook/cellViews/textCell.component';
|
||||
import { OutputAreaComponent } from 'sql/parts/notebook/cellViews/outputArea.component';
|
||||
import { OutputComponent } from 'sql/parts/notebook/cellViews/output.component';
|
||||
import LoadingSpinner from 'sql/parts/modelComponents/loadingSpinner.component';
|
||||
|
||||
export const NotebookModule = (params, selector: string, instantiationService: IInstantiationService): any => {
|
||||
@@ -40,7 +42,9 @@ export const NotebookModule = (params, selector: string, instantiationService: I
|
||||
CodeCellComponent,
|
||||
TextCellComponent,
|
||||
NotebookComponent,
|
||||
ComponentHostDirective
|
||||
ComponentHostDirective,
|
||||
OutputAreaComponent,
|
||||
OutputComponent
|
||||
],
|
||||
entryComponents: [NotebookComponent],
|
||||
imports: [
|
||||
|
||||
54
src/sql/parts/notebook/outputs/common/jsonext.ts
Normal file
54
src/sql/parts/notebook/outputs/common/jsonext.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
/**
|
||||
* A type alias for a JSON primitive.
|
||||
*/
|
||||
export declare type JSONPrimitive = boolean | number | string | null;
|
||||
/**
|
||||
* A type alias for a JSON value.
|
||||
*/
|
||||
export declare type JSONValue = JSONPrimitive | JSONObject | JSONArray;
|
||||
/**
|
||||
* A type definition for a JSON object.
|
||||
*/
|
||||
export interface JSONObject {
|
||||
[key: string]: JSONValue;
|
||||
}
|
||||
/**
|
||||
* A type definition for a JSON array.
|
||||
*/
|
||||
export interface JSONArray extends Array<JSONValue> {
|
||||
}
|
||||
/**
|
||||
* A type definition for a readonly JSON object.
|
||||
*/
|
||||
export interface ReadonlyJSONObject {
|
||||
readonly [key: string]: ReadonlyJSONValue;
|
||||
}
|
||||
/**
|
||||
* A type definition for a readonly JSON array.
|
||||
*/
|
||||
export interface ReadonlyJSONArray extends ReadonlyArray<ReadonlyJSONValue> {
|
||||
}
|
||||
/**
|
||||
* A type alias for a readonly JSON value.
|
||||
*/
|
||||
export declare type ReadonlyJSONValue = JSONPrimitive | ReadonlyJSONObject | ReadonlyJSONArray;
|
||||
/**
|
||||
* Test whether a JSON value is a primitive.
|
||||
*
|
||||
* @param value - The JSON value of interest.
|
||||
*
|
||||
* @returns `true` if the value is a primitive,`false` otherwise.
|
||||
*/
|
||||
export function isPrimitive(value: any): boolean {
|
||||
return (
|
||||
value === null ||
|
||||
typeof value === 'boolean' ||
|
||||
typeof value === 'number' ||
|
||||
typeof value === 'string'
|
||||
);
|
||||
}
|
||||
87
src/sql/parts/notebook/outputs/common/mimemodel.ts
Normal file
87
src/sql/parts/notebook/outputs/common/mimemodel.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
| Copyright (c) Jupyter Development Team.
|
||||
| Distributed under the terms of the Modified BSD License.
|
||||
|----------------------------------------------------------------------------*/
|
||||
import { IRenderMime } from './renderMimeInterfaces';
|
||||
import { ReadonlyJSONObject } from './jsonext';
|
||||
|
||||
/**
|
||||
* The default mime model implementation.
|
||||
*/
|
||||
export class MimeModel implements IRenderMime.IMimeModel {
|
||||
/**
|
||||
* Construct a new mime model.
|
||||
*/
|
||||
constructor(options: MimeModel.IOptions = {}) {
|
||||
this.trusted = !!options.trusted;
|
||||
this._data = options.data || {};
|
||||
this._metadata = options.metadata || {};
|
||||
this._callback = options.callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the model is trusted.
|
||||
*/
|
||||
readonly trusted: boolean;
|
||||
|
||||
/**
|
||||
* The data associated with the model.
|
||||
*/
|
||||
get data(): ReadonlyJSONObject {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
/**
|
||||
* The metadata associated with the model.
|
||||
*/
|
||||
get metadata(): ReadonlyJSONObject {
|
||||
return this._metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the data associated with the model.
|
||||
*
|
||||
* #### Notes
|
||||
* Depending on the implementation of the mime model,
|
||||
* this call may or may not have deferred effects,
|
||||
*/
|
||||
setData(options: IRenderMime.ISetDataOptions): void {
|
||||
this._data = options.data || this._data;
|
||||
this._metadata = options.metadata || this._metadata;
|
||||
this._callback(options);
|
||||
}
|
||||
|
||||
private _callback: (options: IRenderMime.ISetDataOptions) => void;
|
||||
private _data: ReadonlyJSONObject;
|
||||
private _metadata: ReadonlyJSONObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* The namespace for MimeModel class statics.
|
||||
*/
|
||||
export namespace MimeModel {
|
||||
/**
|
||||
* The options used to create a mime model.
|
||||
*/
|
||||
export interface IOptions {
|
||||
/**
|
||||
* Whether the model is trusted. Defaults to `false`.
|
||||
*/
|
||||
trusted?: boolean;
|
||||
|
||||
/**
|
||||
* A callback function for when the data changes.
|
||||
*/
|
||||
callback?: (options: IRenderMime.ISetDataOptions) => void;
|
||||
|
||||
/**
|
||||
* The initial mime data.
|
||||
*/
|
||||
data?: ReadonlyJSONObject;
|
||||
|
||||
/**
|
||||
* The initial mime metadata.
|
||||
*/
|
||||
metadata?: ReadonlyJSONObject;
|
||||
}
|
||||
}
|
||||
494
src/sql/parts/notebook/outputs/common/nbformat.ts
Normal file
494
src/sql/parts/notebook/outputs/common/nbformat.ts
Normal file
@@ -0,0 +1,494 @@
|
||||
// Copyright (c) Jupyter Development Team.
|
||||
// Distributed under the terms of the Modified BSD License.
|
||||
|
||||
// Notebook format interfaces
|
||||
// https://nbformat.readthedocs.io/en/latest/format_description.html
|
||||
// https://github.com/jupyter/nbformat/blob/master/nbformat/v4/nbformat.v4.schema.json
|
||||
|
||||
|
||||
import { JSONObject } from './jsonext';
|
||||
import { nb } from 'sqlops';
|
||||
|
||||
/**
|
||||
* A namespace for nbformat interfaces.
|
||||
*/
|
||||
export namespace nbformat {
|
||||
/**
|
||||
* The major version of the notebook format.
|
||||
*/
|
||||
export const MAJOR_VERSION: number = 4;
|
||||
|
||||
/**
|
||||
* The minor version of the notebook format.
|
||||
*/
|
||||
export const MINOR_VERSION: number = 2;
|
||||
|
||||
/**
|
||||
* The kernelspec metadata.
|
||||
*/
|
||||
export interface IKernelspecMetadata extends JSONObject {
|
||||
name: string;
|
||||
display_name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The language info metatda
|
||||
*/
|
||||
export interface ILanguageInfoMetadata extends JSONObject {
|
||||
name: string;
|
||||
codemirror_mode?: string | JSONObject;
|
||||
file_extension?: string;
|
||||
mimetype?: string;
|
||||
pygments_lexer?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default metadata for the notebook.
|
||||
*/
|
||||
export interface INotebookMetadata extends JSONObject {
|
||||
kernelspec?: IKernelspecMetadata;
|
||||
language_info?: ILanguageInfoMetadata;
|
||||
orig_nbformat: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* The notebook content.
|
||||
*/
|
||||
export interface INotebookContent {
|
||||
metadata: INotebookMetadata;
|
||||
nbformat_minor: number;
|
||||
nbformat: number;
|
||||
cells: ICell[];
|
||||
}
|
||||
|
||||
/**
|
||||
* A multiline string.
|
||||
*/
|
||||
export type MultilineString = string | string[];
|
||||
|
||||
/**
|
||||
* A mime-type keyed dictionary of data.
|
||||
*/
|
||||
export interface IMimeBundle extends JSONObject {
|
||||
[key: string]: MultilineString | JSONObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Media attachments (e.g. inline images).
|
||||
*/
|
||||
export interface IAttachments {
|
||||
[key: string]: IMimeBundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* The code cell's prompt number. Will be null if the cell has not been run.
|
||||
*/
|
||||
export type ExecutionCount = number | null;
|
||||
|
||||
/**
|
||||
* Cell output metadata.
|
||||
*/
|
||||
export type OutputMetadata = JSONObject;
|
||||
|
||||
/**
|
||||
* Validate a mime type/value pair.
|
||||
*
|
||||
* @param type - The mimetype name.
|
||||
*
|
||||
* @param value - The value associated with the type.
|
||||
*
|
||||
* @returns Whether the type/value pair are valid.
|
||||
*/
|
||||
export function validateMimeValue(
|
||||
type: string,
|
||||
value: MultilineString | JSONObject
|
||||
): boolean {
|
||||
// Check if "application/json" or "application/foo+json"
|
||||
const jsonTest = /^application\/(.*?)+\+json$/;
|
||||
const isJSONType = type === 'application/json' || jsonTest.test(type);
|
||||
|
||||
let isString = (x: any) => {
|
||||
return Object.prototype.toString.call(x) === '[object String]';
|
||||
};
|
||||
|
||||
// If it is an array, make sure if is not a JSON type and it is an
|
||||
// array of strings.
|
||||
if (Array.isArray(value)) {
|
||||
if (isJSONType) {
|
||||
return false;
|
||||
}
|
||||
let valid = true;
|
||||
(value as string[]).forEach(v => {
|
||||
if (!isString(v)) {
|
||||
valid = false;
|
||||
}
|
||||
});
|
||||
return valid;
|
||||
}
|
||||
|
||||
// If it is a string, make sure we are not a JSON type.
|
||||
if (isString(value)) {
|
||||
return !isJSONType;
|
||||
}
|
||||
|
||||
// It is not a string, make sure it is a JSON type.
|
||||
if (!isJSONType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// It is a JSON type, make sure it is a valid JSON object.
|
||||
// return JSONExt.isObject(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cell-level metadata.
|
||||
*/
|
||||
export interface IBaseCellMetadata extends JSONObject {
|
||||
/**
|
||||
* Whether the cell is trusted.
|
||||
*
|
||||
* #### Notes
|
||||
* This is not strictly part of the nbformat spec, but it is added by
|
||||
* the contents manager.
|
||||
*
|
||||
* See https://jupyter-notebook.readthedocs.io/en/latest/security.html.
|
||||
*/
|
||||
trusted: boolean;
|
||||
|
||||
/**
|
||||
* The cell's name. If present, must be a non-empty string.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The cell's tags. Tags must be unique, and must not contain commas.
|
||||
*/
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* The base cell interface.
|
||||
*/
|
||||
export interface IBaseCell {
|
||||
/**
|
||||
* String identifying the type of cell.
|
||||
*/
|
||||
cell_type: string;
|
||||
|
||||
/**
|
||||
* Contents of the cell, represented as an array of lines.
|
||||
*/
|
||||
source: MultilineString;
|
||||
|
||||
/**
|
||||
* Cell-level metadata.
|
||||
*/
|
||||
metadata: Partial<ICellMetadata>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata for the raw cell.
|
||||
*/
|
||||
export interface IRawCellMetadata extends IBaseCellMetadata {
|
||||
/**
|
||||
* Raw cell metadata format for nbconvert.
|
||||
*/
|
||||
format: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A raw cell.
|
||||
*/
|
||||
export interface IRawCell extends IBaseCell {
|
||||
/**
|
||||
* String identifying the type of cell.
|
||||
*/
|
||||
cell_type: 'raw';
|
||||
|
||||
/**
|
||||
* Cell-level metadata.
|
||||
*/
|
||||
metadata: Partial<IRawCellMetadata>;
|
||||
|
||||
/**
|
||||
* Cell attachments.
|
||||
*/
|
||||
attachments?: IAttachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* A markdown cell.
|
||||
*/
|
||||
export interface IMarkdownCell extends IBaseCell {
|
||||
/**
|
||||
* String identifying the type of cell.
|
||||
*/
|
||||
cell_type: 'markdown';
|
||||
|
||||
/**
|
||||
* Cell attachments.
|
||||
*/
|
||||
attachments?: IAttachments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Metadata for a code cell.
|
||||
*/
|
||||
export interface ICodeCellMetadata extends IBaseCellMetadata {
|
||||
/**
|
||||
* Whether the cell is collapsed/expanded.
|
||||
*/
|
||||
collapsed: boolean;
|
||||
|
||||
/**
|
||||
* Whether the cell's output is scrolled, unscrolled, or autoscrolled.
|
||||
*/
|
||||
scrolled: boolean | 'auto';
|
||||
}
|
||||
|
||||
/**
|
||||
* A code cell.
|
||||
*/
|
||||
export interface ICodeCell extends IBaseCell {
|
||||
/**
|
||||
* String identifying the type of cell.
|
||||
*/
|
||||
cell_type: 'code';
|
||||
|
||||
/**
|
||||
* Cell-level metadata.
|
||||
*/
|
||||
metadata: Partial<ICodeCellMetadata>;
|
||||
|
||||
/**
|
||||
* Execution, display, or stream outputs.
|
||||
*/
|
||||
outputs: IOutput[];
|
||||
|
||||
/**
|
||||
* The code cell's prompt number. Will be null if the cell has not been run.
|
||||
*/
|
||||
execution_count: ExecutionCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* An unrecognized cell.
|
||||
*/
|
||||
export interface IUnrecognizedCell extends IBaseCell { }
|
||||
|
||||
/**
|
||||
* A cell union type.
|
||||
*/
|
||||
export type ICell = IRawCell | IMarkdownCell | ICodeCell | IUnrecognizedCell;
|
||||
|
||||
/**
|
||||
* Test whether a cell is a raw cell.
|
||||
*/
|
||||
export function isRaw(cell: ICell): cell is IRawCell {
|
||||
return cell.cell_type === 'raw';
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether a cell is a markdown cell.
|
||||
*/
|
||||
export function isMarkdown(cell: ICell): cell is IMarkdownCell {
|
||||
return cell.cell_type === 'markdown';
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether a cell is a code cell.
|
||||
*/
|
||||
export function isCode(cell: ICell): cell is ICodeCell {
|
||||
return cell.cell_type === 'code';
|
||||
}
|
||||
|
||||
/**
|
||||
* A union metadata type.
|
||||
*/
|
||||
export type ICellMetadata =
|
||||
| IBaseCellMetadata
|
||||
| IRawCellMetadata
|
||||
| ICodeCellMetadata;
|
||||
|
||||
/**
|
||||
* The valid output types.
|
||||
*/
|
||||
export type OutputType =
|
||||
| 'execute_result'
|
||||
| 'display_data'
|
||||
| 'stream'
|
||||
| 'error'
|
||||
| 'update_display_data';
|
||||
|
||||
|
||||
/**
|
||||
* Result of executing a code cell.
|
||||
*/
|
||||
export interface IExecuteResult extends nb.ICellOutput {
|
||||
/**
|
||||
* Type of cell output.
|
||||
*/
|
||||
output_type: 'execute_result';
|
||||
|
||||
/**
|
||||
* A result's prompt number.
|
||||
*/
|
||||
execution_count: ExecutionCount;
|
||||
|
||||
/**
|
||||
* A mime-type keyed dictionary of data.
|
||||
*/
|
||||
data: IMimeBundle;
|
||||
|
||||
/**
|
||||
* Cell output metadata.
|
||||
*/
|
||||
metadata: OutputMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data displayed as a result of code cell execution.
|
||||
*/
|
||||
export interface IDisplayData extends nb.ICellOutput {
|
||||
/**
|
||||
* Type of cell output.
|
||||
*/
|
||||
output_type: 'display_data';
|
||||
|
||||
/**
|
||||
* A mime-type keyed dictionary of data.
|
||||
*/
|
||||
data: IMimeBundle;
|
||||
|
||||
/**
|
||||
* Cell output metadata.
|
||||
*/
|
||||
metadata: OutputMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Data displayed as an update to existing display data.
|
||||
*/
|
||||
export interface IDisplayUpdate extends nb.ICellOutput {
|
||||
/**
|
||||
* Type of cell output.
|
||||
*/
|
||||
output_type: 'update_display_data';
|
||||
|
||||
/**
|
||||
* A mime-type keyed dictionary of data.
|
||||
*/
|
||||
data: IMimeBundle;
|
||||
|
||||
/**
|
||||
* Cell output metadata.
|
||||
*/
|
||||
metadata: OutputMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream output from a code cell.
|
||||
*/
|
||||
export interface IStream extends nb.ICellOutput {
|
||||
/**
|
||||
* Type of cell output.
|
||||
*/
|
||||
output_type: 'stream';
|
||||
|
||||
/**
|
||||
* The name of the stream.
|
||||
*/
|
||||
name: StreamType;
|
||||
|
||||
/**
|
||||
* The stream's text output.
|
||||
*/
|
||||
text: MultilineString;
|
||||
}
|
||||
|
||||
/**
|
||||
* An alias for a stream type.
|
||||
*/
|
||||
export type StreamType = 'stdout' | 'stderr';
|
||||
|
||||
/**
|
||||
* Output of an error that occurred during code cell execution.
|
||||
*/
|
||||
export interface IError extends nb.ICellOutput {
|
||||
/**
|
||||
* Type of cell output.
|
||||
*/
|
||||
output_type: 'error';
|
||||
|
||||
/**
|
||||
* The name of the error.
|
||||
*/
|
||||
ename: string;
|
||||
|
||||
/**
|
||||
* The value, or message, of the error.
|
||||
*/
|
||||
evalue: string;
|
||||
|
||||
/**
|
||||
* The error's traceback.
|
||||
*/
|
||||
traceback: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Unrecognized output.
|
||||
*/
|
||||
export interface IUnrecognizedOutput extends nb.ICellOutput { }
|
||||
|
||||
/**
|
||||
* Test whether an output is an execute result.
|
||||
*/
|
||||
export function isExecuteResult(output: IOutput): output is IExecuteResult {
|
||||
return output.output_type === 'execute_result';
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether an output is from display data.
|
||||
*/
|
||||
export function isDisplayData(output: IOutput): output is IDisplayData {
|
||||
return output.output_type === 'display_data';
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether an output is from updated display data.
|
||||
*/
|
||||
export function isDisplayUpdate(output: IOutput): output is IDisplayUpdate {
|
||||
return output.output_type === 'update_display_data';
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether an output is from a stream.
|
||||
*/
|
||||
export function isStream(output: IOutput): output is IStream {
|
||||
return output.output_type === 'stream';
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether an output is from a stream.
|
||||
*/
|
||||
export function isError(output: IOutput): output is IError {
|
||||
return output.output_type === 'error';
|
||||
}
|
||||
|
||||
/**
|
||||
* An output union type.
|
||||
*/
|
||||
export type IOutput =
|
||||
| IUnrecognizedOutput
|
||||
| IExecuteResult
|
||||
| IDisplayData
|
||||
| IStream
|
||||
| IError;
|
||||
}
|
||||
|
||||
export interface ICellOutputWithIdAndTrust extends nb.ICellOutput {
|
||||
id: number;
|
||||
trusted: boolean;
|
||||
}
|
||||
110
src/sql/parts/notebook/outputs/common/outputProcessor.ts
Normal file
110
src/sql/parts/notebook/outputs/common/outputProcessor.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
| Copyright (c) Jupyter Development Team.
|
||||
| Distributed under the terms of the Modified BSD License.
|
||||
|----------------------------------------------------------------------------*/
|
||||
|
||||
import { JSONObject } from './jsonext';
|
||||
import { MimeModel } from './mimemodel';
|
||||
import * as JSONExt from './jsonext';
|
||||
import { nbformat } from './nbformat';
|
||||
import { nb } from 'sqlops';
|
||||
|
||||
/**
|
||||
* A multiline string.
|
||||
*/
|
||||
export type MultilineString = string | string[];
|
||||
|
||||
/**
|
||||
* A mime-type keyed dictionary of data.
|
||||
*/
|
||||
export interface IMimeBundle extends JSONObject {
|
||||
[key: string]: MultilineString | JSONObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data from a notebook output.
|
||||
*/
|
||||
export function getData(output: nb.ICellOutput): JSONObject {
|
||||
let bundle: IMimeBundle = {};
|
||||
if (
|
||||
nbformat.isExecuteResult(output) ||
|
||||
nbformat.isDisplayData(output) ||
|
||||
nbformat.isDisplayUpdate(output)
|
||||
) {
|
||||
bundle = (output as nbformat.IExecuteResult).data;
|
||||
} else if (nbformat.isStream(output)) {
|
||||
if (output.name === 'stderr') {
|
||||
bundle['application/vnd.jupyter.stderr'] = output.text;
|
||||
} else {
|
||||
bundle['application/vnd.jupyter.stdout'] = output.text;
|
||||
}
|
||||
} else if (nbformat.isError(output)) {
|
||||
let traceback = output.traceback.join('\n');
|
||||
bundle['application/vnd.jupyter.stderr'] =
|
||||
traceback || `${output.ename}: ${output.evalue}`;
|
||||
}
|
||||
return convertBundle(bundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata from an output message.
|
||||
*/
|
||||
export function getMetadata(output: nbformat.IOutput): JSONObject {
|
||||
let value: JSONObject = Object.create(null);
|
||||
if (nbformat.isExecuteResult(output) || nbformat.isDisplayData(output)) {
|
||||
for (let key in output.metadata) {
|
||||
value[key] = extract(output.metadata, key);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bundle options given output model options.
|
||||
*/
|
||||
export function getBundleOptions(
|
||||
options: IOutputModelOptions
|
||||
): MimeModel.IOptions {
|
||||
let data = getData(options.value);
|
||||
let metadata = getMetadata(options.value);
|
||||
let trusted = !!options.trusted;
|
||||
return { data, metadata, trusted };
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a value from a JSONObject.
|
||||
*/
|
||||
export function extract(value: JSONObject, key: string): {} {
|
||||
let item = value[key];
|
||||
if (JSONExt.isPrimitive(item)) {
|
||||
return item;
|
||||
}
|
||||
return JSON.parse(JSON.stringify(item));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a mime bundle to mime data.
|
||||
*/
|
||||
function convertBundle(bundle: nbformat.IMimeBundle): JSONObject {
|
||||
let map: JSONObject = Object.create(null);
|
||||
for (let mimeType in bundle) {
|
||||
map[mimeType] = extract(bundle, mimeType);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* The options used to create a notebook output model.
|
||||
*/
|
||||
export interface IOutputModelOptions {
|
||||
/**
|
||||
* The raw output value.
|
||||
*/
|
||||
value: nbformat.IOutput;
|
||||
|
||||
/**
|
||||
* Whether the output is trusted. The default is false.
|
||||
*/
|
||||
trusted?: boolean;
|
||||
}
|
||||
360
src/sql/parts/notebook/outputs/common/renderMimeInterfaces.ts
Normal file
360
src/sql/parts/notebook/outputs/common/renderMimeInterfaces.ts
Normal file
@@ -0,0 +1,360 @@
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
| Copyright (c) Jupyter Development Team.
|
||||
| Distributed under the terms of the Modified BSD License.
|
||||
|----------------------------------------------------------------------------*/
|
||||
import { ReadonlyJSONObject } from './jsonext';
|
||||
|
||||
/**
|
||||
* A namespace for rendermime associated interfaces.
|
||||
*/
|
||||
export namespace IRenderMime {
|
||||
/**
|
||||
* A model for mime data.
|
||||
*/
|
||||
export interface IMimeModel {
|
||||
/**
|
||||
* Whether the data in the model is trusted.
|
||||
*/
|
||||
readonly trusted: boolean;
|
||||
|
||||
/**
|
||||
* The data associated with the model.
|
||||
*/
|
||||
readonly data: ReadonlyJSONObject;
|
||||
|
||||
/**
|
||||
* The metadata associated with the model.
|
||||
*/
|
||||
readonly metadata: ReadonlyJSONObject;
|
||||
|
||||
/**
|
||||
* Set the data associated with the model.
|
||||
*
|
||||
* #### Notes
|
||||
* Calling this function may trigger an asynchronous operation
|
||||
* that could cause the renderer to be rendered with a new model
|
||||
* containing the new data.
|
||||
*/
|
||||
setData(options: ISetDataOptions): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The options used to update a mime model.
|
||||
*/
|
||||
export interface ISetDataOptions {
|
||||
/**
|
||||
* The new data object.
|
||||
*/
|
||||
data?: ReadonlyJSONObject;
|
||||
|
||||
/**
|
||||
* The new metadata object.
|
||||
*/
|
||||
metadata?: ReadonlyJSONObject;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The options used to initialize a document widget factory.
|
||||
*
|
||||
* This interface is intended to be used by mime renderer extensions
|
||||
* to define a document opener that uses its renderer factory.
|
||||
*/
|
||||
export interface IDocumentWidgetFactoryOptions {
|
||||
/**
|
||||
* The name of the widget to display in dialogs.
|
||||
*/
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* The name of the document model type.
|
||||
*/
|
||||
readonly modelName?: string;
|
||||
|
||||
/**
|
||||
* The primary file type of the widget.
|
||||
*/
|
||||
readonly primaryFileType: string;
|
||||
|
||||
/**
|
||||
* The file types the widget can view.
|
||||
*/
|
||||
readonly fileTypes: ReadonlyArray<string>;
|
||||
|
||||
/**
|
||||
* The file types for which the factory should be the default.
|
||||
*/
|
||||
readonly defaultFor?: ReadonlyArray<string>;
|
||||
|
||||
/**
|
||||
* The file types for which the factory should be the default for rendering,
|
||||
* if that is different than the default factory (which may be for editing)
|
||||
* If undefined, then it will fall back on the default file type.
|
||||
*/
|
||||
readonly defaultRendered?: ReadonlyArray<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A file type to associate with the renderer.
|
||||
*/
|
||||
export interface IFileType {
|
||||
/**
|
||||
* The name of the file type.
|
||||
*/
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* The mime types associated the file type.
|
||||
*/
|
||||
readonly mimeTypes: ReadonlyArray<string>;
|
||||
|
||||
/**
|
||||
* The extensions of the file type (e.g. `".txt"`). Can be a compound
|
||||
* extension (e.g. `".table.json`).
|
||||
*/
|
||||
readonly extensions: ReadonlyArray<string>;
|
||||
|
||||
/**
|
||||
* An optional display name for the file type.
|
||||
*/
|
||||
readonly displayName?: string;
|
||||
|
||||
/**
|
||||
* An optional pattern for a file name (e.g. `^Dockerfile$`).
|
||||
*/
|
||||
readonly pattern?: string;
|
||||
|
||||
/**
|
||||
* The icon class name for the file type.
|
||||
*/
|
||||
readonly iconClass?: string;
|
||||
|
||||
/**
|
||||
* The icon label for the file type.
|
||||
*/
|
||||
readonly iconLabel?: string;
|
||||
|
||||
/**
|
||||
* The file format for the file type ('text', 'base64', or 'json').
|
||||
*/
|
||||
readonly fileFormat?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface for using a RenderMime.IRenderer for output and read-only documents.
|
||||
*/
|
||||
export interface IExtension {
|
||||
/**
|
||||
* The ID of the extension.
|
||||
*
|
||||
* #### Notes
|
||||
* The convention for extension IDs in JupyterLab is the full NPM package
|
||||
* name followed by a colon and a unique string token, e.g.
|
||||
* `'@jupyterlab/apputils-extension:settings'` or `'foo-extension:bar'`.
|
||||
*/
|
||||
readonly id: string;
|
||||
|
||||
/**
|
||||
* A renderer factory to be registered to render the MIME type.
|
||||
*/
|
||||
readonly rendererFactory: IRendererFactory;
|
||||
|
||||
/**
|
||||
* The rank passed to `RenderMime.addFactory`. If not given,
|
||||
* defaults to the `defaultRank` of the factory.
|
||||
*/
|
||||
readonly rank?: number;
|
||||
|
||||
/**
|
||||
* The timeout after user activity to re-render the data.
|
||||
*/
|
||||
readonly renderTimeout?: number;
|
||||
|
||||
/**
|
||||
* Preferred data type from the model. Defaults to `string`.
|
||||
*/
|
||||
readonly dataType?: 'string' | 'json';
|
||||
|
||||
/**
|
||||
* The options used to open a document with the renderer factory.
|
||||
*/
|
||||
readonly documentWidgetFactoryOptions?:
|
||||
| IDocumentWidgetFactoryOptions
|
||||
| ReadonlyArray<IDocumentWidgetFactoryOptions>;
|
||||
|
||||
/**
|
||||
* The optional file type associated with the extension.
|
||||
*/
|
||||
readonly fileTypes?: ReadonlyArray<IFileType>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface for a module that exports an extension or extensions as
|
||||
* the default value.
|
||||
*/
|
||||
export interface IExtensionModule {
|
||||
/**
|
||||
* The default export.
|
||||
*/
|
||||
readonly default: IExtension | ReadonlyArray<IExtension>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A widget which displays the contents of a mime model.
|
||||
*/
|
||||
export interface IRenderer {
|
||||
/**
|
||||
* Render a mime model.
|
||||
*
|
||||
* @param model - The mime model to render.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*
|
||||
* #### Notes
|
||||
* This method may be called multiple times during the lifetime
|
||||
* of the widget to update it if and when new data is available.
|
||||
*/
|
||||
renderModel(model: IRenderMime.IMimeModel): Promise<void>;
|
||||
|
||||
/**
|
||||
* Node to be updated by the renderer
|
||||
*/
|
||||
node: HTMLElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface for a renderer factory.
|
||||
*/
|
||||
export interface IRendererFactory {
|
||||
/**
|
||||
* Whether the factory is a "safe" factory.
|
||||
*
|
||||
* #### Notes
|
||||
* A "safe" factory produces renderer widgets which can render
|
||||
* untrusted model data in a usable way. *All* renderers must
|
||||
* handle untrusted data safely, but some may simply failover
|
||||
* with a "Run cell to view output" message. A "safe" renderer
|
||||
* is an indication that its sanitized output will be useful.
|
||||
*/
|
||||
readonly safe: boolean;
|
||||
|
||||
/**
|
||||
* The mime types handled by this factory.
|
||||
*/
|
||||
readonly mimeTypes: ReadonlyArray<string>;
|
||||
|
||||
/**
|
||||
* The default rank of the factory. If not given, defaults to 100.
|
||||
*/
|
||||
readonly defaultRank?: number;
|
||||
|
||||
/**
|
||||
* Create a renderer which displays the mime data.
|
||||
*
|
||||
* @param options - The options used to render the data.
|
||||
*/
|
||||
createRenderer(options: IRendererOptions): IRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* The options used to create a renderer.
|
||||
*/
|
||||
export interface IRendererOptions {
|
||||
/**
|
||||
* The preferred mimeType to render.
|
||||
*/
|
||||
mimeType: string;
|
||||
|
||||
/**
|
||||
* The html sanitizer.
|
||||
*/
|
||||
sanitizer: ISanitizer;
|
||||
|
||||
/**
|
||||
* An optional url resolver.
|
||||
*/
|
||||
resolver: IResolver | null;
|
||||
|
||||
/**
|
||||
* An optional link handler.
|
||||
*/
|
||||
linkHandler: ILinkHandler | null;
|
||||
|
||||
/**
|
||||
* The LaTeX typesetter.
|
||||
*/
|
||||
latexTypesetter: ILatexTypesetter | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that handles html sanitization.
|
||||
*/
|
||||
export interface ISanitizer {
|
||||
/**
|
||||
* Sanitize an HTML string.
|
||||
*/
|
||||
sanitize(dirty: string): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that handles links on a node.
|
||||
*/
|
||||
export interface ILinkHandler {
|
||||
/**
|
||||
* Add the link handler to the node.
|
||||
*
|
||||
* @param node: the node for which to handle the link.
|
||||
*
|
||||
* @param path: the path to open when the link is clicked.
|
||||
*
|
||||
* @param id: an optional element id to scroll to when the path is opened.
|
||||
*/
|
||||
handleLink(node: HTMLElement, path: string, id?: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that resolves relative URLs.
|
||||
*/
|
||||
export interface IResolver {
|
||||
/**
|
||||
* Resolve a relative url to a correct server path.
|
||||
*/
|
||||
resolveUrl(url: string): Promise<string>;
|
||||
|
||||
/**
|
||||
* Get the download url of a given absolute server path.
|
||||
*/
|
||||
getDownloadUrl(path: string): Promise<string>;
|
||||
|
||||
/**
|
||||
* Whether the URL should be handled by the resolver
|
||||
* or not.
|
||||
*
|
||||
* #### Notes
|
||||
* This is similar to the `isLocal` check in `URLExt`,
|
||||
* but can also perform additional checks on whether the
|
||||
* resolver should handle a given URL.
|
||||
*/
|
||||
isLocal?: (url: string) => boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface for a LaTeX typesetter.
|
||||
*/
|
||||
export interface ILatexTypesetter {
|
||||
/**
|
||||
* Typeset a DOM element.
|
||||
*
|
||||
* @param element - the DOM element to typeset. The typesetting may
|
||||
* happen synchronously or asynchronously.
|
||||
*
|
||||
* #### Notes
|
||||
* The application-wide rendermime object has a settable
|
||||
* `latexTypesetter` property which is used wherever LaTeX
|
||||
* typesetting is required. Extensions wishing to provide their
|
||||
* own typesetter may replace that on the global `lab.rendermime`.
|
||||
*/
|
||||
typeset(element: HTMLElement): void;
|
||||
}
|
||||
}
|
||||
184
src/sql/parts/notebook/outputs/common/url.ts
Normal file
184
src/sql/parts/notebook/outputs/common/url.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
// Copyright (c) Jupyter Development Team.
|
||||
// Distributed under the terms of the Modified BSD License.
|
||||
|
||||
import { JSONObject } from './jsonext';
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
||||
/**
|
||||
* The namespace for URL-related functions.
|
||||
*/
|
||||
export namespace URLExt {
|
||||
/**
|
||||
* Normalize a url.
|
||||
*/
|
||||
export function normalize(url: string): string {
|
||||
return URI.parse(url).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Join a sequence of url components and normalizes as in node `path.join`.
|
||||
*
|
||||
* @param parts - The url components.
|
||||
*
|
||||
* @returns the joined url.
|
||||
*/
|
||||
export function join(...parts: string[]): string {
|
||||
parts = parts || [];
|
||||
|
||||
// Isolate the top element.
|
||||
const top = parts[0] || '';
|
||||
|
||||
// Check whether protocol shorthand is being used.
|
||||
const shorthand = top.indexOf('//') === 0;
|
||||
|
||||
// Parse the top element into a header collection.
|
||||
const header = top.match(/(\w+)(:)(\/\/)?/);
|
||||
const protocol = header && header[1];
|
||||
const colon = protocol && header[2];
|
||||
const slashes = colon && header[3];
|
||||
|
||||
// Construct the URL prefix.
|
||||
const prefix = shorthand
|
||||
? '//'
|
||||
: [protocol, colon, slashes].filter(str => str).join('');
|
||||
|
||||
// Construct the URL body omitting the prefix of the top value.
|
||||
const body = [top.indexOf(prefix) === 0 ? top.replace(prefix, '') : top]
|
||||
// Filter out top value if empty.
|
||||
.filter(str => str)
|
||||
// Remove leading slashes in all subsequent URL body elements.
|
||||
.concat(parts.slice(1).map(str => str.replace(/^\//, '')))
|
||||
.join('/')
|
||||
// Replace multiple slashes with one.
|
||||
.replace(/\/+/g, '/');
|
||||
|
||||
return prefix + body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the components of a multi-segment url.
|
||||
*
|
||||
* @param url - The url to encode.
|
||||
*
|
||||
* @returns the encoded url.
|
||||
*
|
||||
* #### Notes
|
||||
* Preserves the `'/'` separators.
|
||||
* Should not include the base url, since all parts are escaped.
|
||||
*/
|
||||
export function encodeParts(url: string): string {
|
||||
return join(...url.split('/').map(encodeURIComponent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a serialized object string suitable for a query.
|
||||
*
|
||||
* @param object - The source object.
|
||||
*
|
||||
* @returns an encoded url query.
|
||||
*
|
||||
* #### Notes
|
||||
* Modified version of [stackoverflow](http://stackoverflow.com/a/30707423).
|
||||
*/
|
||||
export function objectToQueryString(value: JSONObject): string {
|
||||
const keys = Object.keys(value);
|
||||
|
||||
if (!keys.length) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return (
|
||||
'?' +
|
||||
keys
|
||||
.map(key => {
|
||||
const content = encodeURIComponent(String(value[key]));
|
||||
|
||||
return key + (content ? '=' + content : '');
|
||||
})
|
||||
.join('&')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a parsed object that represents the values in a query string.
|
||||
*/
|
||||
export function queryStringToObject(
|
||||
value: string
|
||||
): { [key: string]: string } {
|
||||
return value
|
||||
.replace(/^\?/, '')
|
||||
.split('&')
|
||||
.reduce(
|
||||
(acc, val) => {
|
||||
const [key, value] = val.split('=');
|
||||
|
||||
acc[key] = decodeURIComponent(value || '');
|
||||
|
||||
return acc;
|
||||
},
|
||||
{} as { [key: string]: string }
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the url is a local url.
|
||||
*
|
||||
* #### Notes
|
||||
* This function returns `false` for any fully qualified url, including
|
||||
* `data:`, `file:`, and `//` protocol URLs.
|
||||
*/
|
||||
export function isLocal(url: string): boolean {
|
||||
// If if doesn't have a scheme such as file: or http:// it's local
|
||||
return !!URI.parse(url).scheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface for a URL object
|
||||
*/
|
||||
export interface IUrl {
|
||||
/**
|
||||
* The full URL string that was parsed with both the protocol and host
|
||||
* components converted to lower-case.
|
||||
*/
|
||||
href?: string;
|
||||
|
||||
/**
|
||||
* Identifies the URL's lower-cased protocol scheme.
|
||||
*/
|
||||
protocol?: string;
|
||||
|
||||
/**
|
||||
* The full lower-cased host portion of the URL, including the port if
|
||||
* specified.
|
||||
*/
|
||||
host?: string;
|
||||
|
||||
/**
|
||||
* The lower-cased host name portion of the host component without the
|
||||
* port included.
|
||||
*/
|
||||
hostname?: string;
|
||||
|
||||
/**
|
||||
* The numeric port portion of the host component.
|
||||
*/
|
||||
port?: string;
|
||||
|
||||
/**
|
||||
* The entire path section of the URL.
|
||||
*/
|
||||
pathname?: string;
|
||||
|
||||
/**
|
||||
* The "fragment" portion of the URL including the leading ASCII hash
|
||||
* `(#)` character
|
||||
*/
|
||||
hash?: string;
|
||||
|
||||
/**
|
||||
* The search element, including leading question mark (`'?'`), if any,
|
||||
* of the URL.
|
||||
*/
|
||||
search?: string;
|
||||
}
|
||||
}
|
||||
94
src/sql/parts/notebook/outputs/factories.ts
Normal file
94
src/sql/parts/notebook/outputs/factories.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
| Copyright (c) Jupyter Development Team.
|
||||
| Distributed under the terms of the Modified BSD License.
|
||||
|----------------------------------------------------------------------------*/
|
||||
|
||||
import * as widgets from './widgets';
|
||||
import { IRenderMime } from './common/renderMimeInterfaces';
|
||||
|
||||
/**
|
||||
* A mime renderer factory for raw html.
|
||||
*/
|
||||
export const htmlRendererFactory: IRenderMime.IRendererFactory = {
|
||||
safe: true,
|
||||
mimeTypes: ['text/html'],
|
||||
defaultRank: 50,
|
||||
createRenderer: options => new widgets.RenderedHTML(options)
|
||||
};
|
||||
|
||||
/**
|
||||
* A mime renderer factory for images.
|
||||
*/
|
||||
export const imageRendererFactory: IRenderMime.IRendererFactory = {
|
||||
safe: true,
|
||||
mimeTypes: ['image/bmp', 'image/png', 'image/jpeg', 'image/gif'],
|
||||
defaultRank: 90,
|
||||
createRenderer: options => new widgets.RenderedImage(options)
|
||||
};
|
||||
|
||||
// /**
|
||||
// * A mime renderer factory for LaTeX.
|
||||
// */
|
||||
// export const latexRendererFactory: IRenderMime.IRendererFactory = {
|
||||
// safe: true,
|
||||
// mimeTypes: ['text/latex'],
|
||||
// defaultRank: 70,
|
||||
// createRenderer: options => new widgets.RenderedLatex(options)
|
||||
// };
|
||||
|
||||
// /**
|
||||
// * A mime renderer factory for Markdown.
|
||||
// */
|
||||
// export const markdownRendererFactory: IRenderMime.IRendererFactory = {
|
||||
// safe: true,
|
||||
// mimeTypes: ['text/markdown'],
|
||||
// defaultRank: 60,
|
||||
// createRenderer: options => new widgets.RenderedMarkdown(options)
|
||||
// };
|
||||
|
||||
/**
|
||||
* A mime renderer factory for svg.
|
||||
*/
|
||||
export const svgRendererFactory: IRenderMime.IRendererFactory = {
|
||||
safe: false,
|
||||
mimeTypes: ['image/svg+xml'],
|
||||
defaultRank: 80,
|
||||
createRenderer: options => new widgets.RenderedSVG(options)
|
||||
};
|
||||
|
||||
/**
|
||||
* A mime renderer factory for plain and jupyter console text data.
|
||||
*/
|
||||
export const textRendererFactory: IRenderMime.IRendererFactory = {
|
||||
safe: true,
|
||||
mimeTypes: [
|
||||
'text/plain',
|
||||
'application/vnd.jupyter.stdout',
|
||||
'application/vnd.jupyter.stderr'
|
||||
],
|
||||
defaultRank: 120,
|
||||
createRenderer: options => new widgets.RenderedText(options)
|
||||
};
|
||||
|
||||
/**
|
||||
* A placeholder factory for deprecated rendered JavaScript.
|
||||
*/
|
||||
export const javaScriptRendererFactory: IRenderMime.IRendererFactory = {
|
||||
safe: false,
|
||||
mimeTypes: ['text/javascript', 'application/javascript'],
|
||||
defaultRank: 110,
|
||||
createRenderer: options => new widgets.RenderedJavaScript(options)
|
||||
};
|
||||
|
||||
/**
|
||||
* The standard factories provided by the rendermime package.
|
||||
*/
|
||||
export const standardRendererFactories: ReadonlyArray<IRenderMime.IRendererFactory> = [
|
||||
htmlRendererFactory,
|
||||
// markdownRendererFactory,
|
||||
// latexRendererFactory,
|
||||
svgRendererFactory,
|
||||
imageRendererFactory,
|
||||
javaScriptRendererFactory,
|
||||
textRendererFactory
|
||||
];
|
||||
352
src/sql/parts/notebook/outputs/registry.ts
Normal file
352
src/sql/parts/notebook/outputs/registry.ts
Normal file
@@ -0,0 +1,352 @@
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
| Copyright (c) Jupyter Development Team.
|
||||
| Distributed under the terms of the Modified BSD License.
|
||||
|----------------------------------------------------------------------------*/
|
||||
import { IRenderMime } from './common/renderMimeInterfaces';
|
||||
import { MimeModel } from './common/mimemodel';
|
||||
import { ReadonlyJSONObject } from './common/jsonext';
|
||||
import { defaultSanitizer } from './sanitizer';
|
||||
|
||||
/**
|
||||
* An object which manages mime renderer factories.
|
||||
*
|
||||
* This object is used to render mime models using registered mime
|
||||
* renderers, selecting the preferred mime renderer to render the
|
||||
* model into a widget.
|
||||
*
|
||||
* #### Notes
|
||||
* This class is not intended to be subclassed.
|
||||
*/
|
||||
export class RenderMimeRegistry {
|
||||
/**
|
||||
* Construct a new rendermime.
|
||||
*
|
||||
* @param options - The options for initializing the instance.
|
||||
*/
|
||||
constructor(options: RenderMimeRegistry.IOptions = {}) {
|
||||
// Parse the options.
|
||||
this.resolver = options.resolver || null;
|
||||
this.linkHandler = options.linkHandler || null;
|
||||
this.latexTypesetter = options.latexTypesetter || null;
|
||||
this.sanitizer = options.sanitizer || defaultSanitizer;
|
||||
|
||||
// Add the initial factories.
|
||||
if (options.initialFactories) {
|
||||
for (let factory of options.initialFactories) {
|
||||
this.addFactory(factory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The sanitizer used by the rendermime instance.
|
||||
*/
|
||||
readonly sanitizer: IRenderMime.ISanitizer;
|
||||
|
||||
/**
|
||||
* The object used to resolve relative urls for the rendermime instance.
|
||||
*/
|
||||
readonly resolver: IRenderMime.IResolver | null;
|
||||
|
||||
/**
|
||||
* The object used to handle path opening links.
|
||||
*/
|
||||
readonly linkHandler: IRenderMime.ILinkHandler | null;
|
||||
|
||||
/**
|
||||
* The LaTeX typesetter for the rendermime.
|
||||
*/
|
||||
readonly latexTypesetter: IRenderMime.ILatexTypesetter | null;
|
||||
|
||||
/**
|
||||
* The ordered list of mimeTypes.
|
||||
*/
|
||||
get mimeTypes(): ReadonlyArray<string> {
|
||||
return this._types || (this._types = Private.sortedTypes(this._ranks));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the preferred mime type for a mime bundle.
|
||||
*
|
||||
* @param bundle - The bundle of mime data.
|
||||
*
|
||||
* @param safe - How to consider safe/unsafe factories. If 'ensure',
|
||||
* it will only consider safe factories. If 'any', any factory will be
|
||||
* considered. If 'prefer', unsafe factories will be considered, but
|
||||
* only after the safe options have been exhausted.
|
||||
*
|
||||
* @returns The preferred mime type from the available factories,
|
||||
* or `undefined` if the mime type cannot be rendered.
|
||||
*/
|
||||
preferredMimeType(
|
||||
bundle: ReadonlyJSONObject,
|
||||
safe: 'ensure' | 'prefer' | 'any' = 'ensure'
|
||||
): string | undefined {
|
||||
// Try to find a safe factory first, if preferred.
|
||||
if (safe === 'ensure' || safe === 'prefer') {
|
||||
for (let mt of this.mimeTypes) {
|
||||
if (mt in bundle && this._factories[mt].safe) {
|
||||
return mt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (safe !== 'ensure') {
|
||||
// Otherwise, search for the best factory among all factories.
|
||||
for (let mt of this.mimeTypes) {
|
||||
if (mt in bundle) {
|
||||
return mt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, no matching mime type exists.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a renderer for a mime type.
|
||||
*
|
||||
* @param mimeType - The mime type of interest.
|
||||
*
|
||||
* @returns A new renderer for the given mime type.
|
||||
*
|
||||
* @throws An error if no factory exists for the mime type.
|
||||
*/
|
||||
createRenderer(mimeType: string): IRenderMime.IRenderer {
|
||||
// Throw an error if no factory exists for the mime type.
|
||||
if (!(mimeType in this._factories)) {
|
||||
throw new Error(`No factory for mime type: '${mimeType}'`);
|
||||
}
|
||||
|
||||
// Invoke the best factory for the given mime type.
|
||||
return this._factories[mimeType].createRenderer({
|
||||
mimeType,
|
||||
resolver: this.resolver,
|
||||
sanitizer: this.sanitizer,
|
||||
linkHandler: this.linkHandler,
|
||||
latexTypesetter: this.latexTypesetter
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new mime model. This is a convenience method.
|
||||
*
|
||||
* @options - The options used to create the model.
|
||||
*
|
||||
* @returns A new mime model.
|
||||
*/
|
||||
createModel(options: MimeModel.IOptions = {}): MimeModel {
|
||||
return new MimeModel(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a clone of this rendermime instance.
|
||||
*
|
||||
* @param options - The options for configuring the clone.
|
||||
*
|
||||
* @returns A new independent clone of the rendermime.
|
||||
*/
|
||||
clone(options: RenderMimeRegistry.ICloneOptions = {}): RenderMimeRegistry {
|
||||
// Create the clone.
|
||||
let clone = new RenderMimeRegistry({
|
||||
resolver: options.resolver || this.resolver || undefined,
|
||||
sanitizer: options.sanitizer || this.sanitizer || undefined,
|
||||
linkHandler: options.linkHandler || this.linkHandler || undefined,
|
||||
latexTypesetter: options.latexTypesetter || this.latexTypesetter
|
||||
});
|
||||
|
||||
// Clone the internal state.
|
||||
clone._factories = { ...this._factories };
|
||||
clone._ranks = { ...this._ranks };
|
||||
clone._id = this._id;
|
||||
|
||||
// Return the cloned object.
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the renderer factory registered for a mime type.
|
||||
*
|
||||
* @param mimeType - The mime type of interest.
|
||||
*
|
||||
* @returns The factory for the mime type, or `undefined`.
|
||||
*/
|
||||
getFactory(mimeType: string): IRenderMime.IRendererFactory | undefined {
|
||||
return this._factories[mimeType];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a renderer factory to the rendermime.
|
||||
*
|
||||
* @param factory - The renderer factory of interest.
|
||||
*
|
||||
* @param rank - The rank of the renderer. A lower rank indicates
|
||||
* a higher priority for rendering. If not given, the rank will
|
||||
* defer to the `defaultRank` of the factory. If no `defaultRank`
|
||||
* is given, it will default to 100.
|
||||
*
|
||||
* #### Notes
|
||||
* The renderer will replace an existing renderer for the given
|
||||
* mimeType.
|
||||
*/
|
||||
addFactory(factory: IRenderMime.IRendererFactory, rank?: number): void {
|
||||
if (rank === undefined) {
|
||||
rank = factory.defaultRank;
|
||||
if (rank === undefined) {
|
||||
rank = 100;
|
||||
}
|
||||
}
|
||||
for (let mt of factory.mimeTypes) {
|
||||
this._factories[mt] = factory;
|
||||
this._ranks[mt] = { rank, id: this._id++ };
|
||||
}
|
||||
this._types = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a mime type.
|
||||
*
|
||||
* @param mimeType - The mime type of interest.
|
||||
*/
|
||||
removeMimeType(mimeType: string): void {
|
||||
delete this._factories[mimeType];
|
||||
delete this._ranks[mimeType];
|
||||
this._types = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rank for a given mime type.
|
||||
*
|
||||
* @param mimeType - The mime type of interest.
|
||||
*
|
||||
* @returns The rank of the mime type or undefined.
|
||||
*/
|
||||
getRank(mimeType: string): number | undefined {
|
||||
let rank = this._ranks[mimeType];
|
||||
return rank && rank.rank;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rank of a given mime type.
|
||||
*
|
||||
* @param mimeType - The mime type of interest.
|
||||
*
|
||||
* @param rank - The new rank to assign.
|
||||
*
|
||||
* #### Notes
|
||||
* This is a no-op if the mime type is not registered.
|
||||
*/
|
||||
setRank(mimeType: string, rank: number): void {
|
||||
if (!this._ranks[mimeType]) {
|
||||
return;
|
||||
}
|
||||
let id = this._id++;
|
||||
this._ranks[mimeType] = { rank, id };
|
||||
this._types = null;
|
||||
}
|
||||
|
||||
private _id = 0;
|
||||
private _ranks: Private.RankMap = {};
|
||||
private _types: string[] | null = null;
|
||||
private _factories: Private.FactoryMap = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* The namespace for `RenderMimeRegistry` class statics.
|
||||
*/
|
||||
export namespace RenderMimeRegistry {
|
||||
/**
|
||||
* The options used to initialize a rendermime instance.
|
||||
*/
|
||||
export interface IOptions {
|
||||
/**
|
||||
* Initial factories to add to the rendermime instance.
|
||||
*/
|
||||
initialFactories?: ReadonlyArray<IRenderMime.IRendererFactory>;
|
||||
|
||||
/**
|
||||
* The sanitizer used to sanitize untrusted html inputs.
|
||||
*
|
||||
* If not given, a default sanitizer will be used.
|
||||
*/
|
||||
sanitizer?: IRenderMime.ISanitizer;
|
||||
|
||||
/**
|
||||
* The initial resolver object.
|
||||
*
|
||||
* The default is `null`.
|
||||
*/
|
||||
resolver?: IRenderMime.IResolver;
|
||||
|
||||
/**
|
||||
* An optional path handler.
|
||||
*/
|
||||
linkHandler?: IRenderMime.ILinkHandler;
|
||||
|
||||
/**
|
||||
* An optional LaTeX typesetter.
|
||||
*/
|
||||
latexTypesetter?: IRenderMime.ILatexTypesetter;
|
||||
}
|
||||
|
||||
/**
|
||||
* The options used to clone a rendermime instance.
|
||||
*/
|
||||
export interface ICloneOptions {
|
||||
/**
|
||||
* The new sanitizer used to sanitize untrusted html inputs.
|
||||
*/
|
||||
sanitizer?: IRenderMime.ISanitizer;
|
||||
|
||||
/**
|
||||
* The new resolver object.
|
||||
*/
|
||||
resolver?: IRenderMime.IResolver;
|
||||
|
||||
/**
|
||||
* The new path handler.
|
||||
*/
|
||||
linkHandler?: IRenderMime.ILinkHandler;
|
||||
|
||||
/**
|
||||
* The new LaTeX typesetter.
|
||||
*/
|
||||
latexTypesetter?: IRenderMime.ILatexTypesetter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The namespace for the module implementation details.
|
||||
*/
|
||||
namespace Private {
|
||||
/**
|
||||
* A type alias for a mime rank and tie-breaking id.
|
||||
*/
|
||||
export type RankPair = { readonly id: number; readonly rank: number };
|
||||
|
||||
/**
|
||||
* A type alias for a mapping of mime type -> rank pair.
|
||||
*/
|
||||
export type RankMap = { [key: string]: RankPair };
|
||||
|
||||
/**
|
||||
* A type alias for a mapping of mime type -> ordered factories.
|
||||
*/
|
||||
export type FactoryMap = { [key: string]: IRenderMime.IRendererFactory };
|
||||
|
||||
/**
|
||||
* Get the mime types in the map, ordered by rank.
|
||||
*/
|
||||
export function sortedTypes(map: RankMap): string[] {
|
||||
return Object.keys(map).sort((a, b) => {
|
||||
let p1 = map[a];
|
||||
let p2 = map[b];
|
||||
if (p1.rank !== p2.rank) {
|
||||
return p1.rank - p2.rank;
|
||||
}
|
||||
return p1.id - p2.id;
|
||||
});
|
||||
}
|
||||
}
|
||||
629
src/sql/parts/notebook/outputs/renderers.ts
Normal file
629
src/sql/parts/notebook/outputs/renderers.ts
Normal file
@@ -0,0 +1,629 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
| Copyright (c) Jupyter Development Team.
|
||||
| Distributed under the terms of the Modified BSD License.
|
||||
|----------------------------------------------------------------------------*/
|
||||
|
||||
import { default as AnsiUp } from 'ansi_up';
|
||||
import { IRenderMime } from './common/renderMimeInterfaces';
|
||||
import { URLExt } from './common/url';
|
||||
import URI from 'vs/base/common/uri';
|
||||
|
||||
|
||||
/**
|
||||
* Render HTML into a host node.
|
||||
*
|
||||
* @params options - The options for rendering.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
export function renderHTML(options: renderHTML.IOptions): Promise<void> {
|
||||
// Unpack the options.
|
||||
let {
|
||||
host,
|
||||
source,
|
||||
trusted,
|
||||
sanitizer,
|
||||
resolver,
|
||||
linkHandler,
|
||||
shouldTypeset,
|
||||
latexTypesetter
|
||||
} = options;
|
||||
|
||||
let originalSource = source;
|
||||
|
||||
// Bail early if the source is empty.
|
||||
if (!source) {
|
||||
host.textContent = '';
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// Sanitize the source if it is not trusted. This removes all
|
||||
// `<script>` tags as well as other potentially harmful HTML.
|
||||
if (!trusted) {
|
||||
originalSource = `${source}`;
|
||||
source = sanitizer.sanitize(source);
|
||||
}
|
||||
|
||||
// Set the inner HTML of the host.
|
||||
host.innerHTML = source;
|
||||
|
||||
if (host.getElementsByTagName('script').length > 0) {
|
||||
// If output it trusted, eval any script tags contained in the HTML.
|
||||
// This is not done automatically by the browser when script tags are
|
||||
// created by setting `innerHTML`.
|
||||
if (trusted) {
|
||||
Private.evalInnerHTMLScriptTags(host);
|
||||
} else {
|
||||
const container = document.createElement('div');
|
||||
const warning = document.createElement('pre');
|
||||
warning.textContent =
|
||||
'This HTML output contains inline scripts. Are you sure that you want to run arbitrary Javascript within your JupyterLab session?';
|
||||
const runButton = document.createElement('button');
|
||||
runButton.textContent = 'Run';
|
||||
runButton.onclick = event => {
|
||||
host.innerHTML = originalSource;
|
||||
Private.evalInnerHTMLScriptTags(host);
|
||||
host.removeChild(host.firstChild);
|
||||
};
|
||||
container.appendChild(warning);
|
||||
container.appendChild(runButton);
|
||||
host.insertBefore(container, host.firstChild);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle default behavior of nodes.
|
||||
Private.handleDefaults(host, resolver);
|
||||
|
||||
// Patch the urls if a resolver is available.
|
||||
let promise: Promise<void>;
|
||||
if (resolver) {
|
||||
promise = Private.handleUrls(host, resolver, linkHandler);
|
||||
} else {
|
||||
promise = Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// Return the final rendered promise.
|
||||
return promise.then(() => {
|
||||
if (shouldTypeset && latexTypesetter) {
|
||||
latexTypesetter.typeset(host);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The namespace for the `renderHTML` function statics.
|
||||
*/
|
||||
export namespace renderHTML {
|
||||
/**
|
||||
* The options for the `renderHTML` function.
|
||||
*/
|
||||
export interface IOptions {
|
||||
/**
|
||||
* The host node for the rendered HTML.
|
||||
*/
|
||||
host: HTMLElement;
|
||||
|
||||
/**
|
||||
* The HTML source to render.
|
||||
*/
|
||||
source: string;
|
||||
|
||||
/**
|
||||
* Whether the source is trusted.
|
||||
*/
|
||||
trusted: boolean;
|
||||
|
||||
/**
|
||||
* The html sanitizer for untrusted source.
|
||||
*/
|
||||
sanitizer: IRenderMime.ISanitizer;
|
||||
|
||||
/**
|
||||
* An optional url resolver.
|
||||
*/
|
||||
resolver: IRenderMime.IResolver | null;
|
||||
|
||||
/**
|
||||
* An optional link handler.
|
||||
*/
|
||||
linkHandler: IRenderMime.ILinkHandler | null;
|
||||
|
||||
/**
|
||||
* Whether the node should be typeset.
|
||||
*/
|
||||
shouldTypeset: boolean;
|
||||
|
||||
/**
|
||||
* The LaTeX typesetter for the application.
|
||||
*/
|
||||
latexTypesetter: IRenderMime.ILatexTypesetter | null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an image into a host node.
|
||||
*
|
||||
* @params options - The options for rendering.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
export function renderImage(
|
||||
options: renderImage.IRenderOptions
|
||||
): Promise<void> {
|
||||
// Unpack the options.
|
||||
let {
|
||||
host,
|
||||
mimeType,
|
||||
source,
|
||||
width,
|
||||
height,
|
||||
needsBackground,
|
||||
unconfined
|
||||
} = options;
|
||||
|
||||
// Clear the content in the host.
|
||||
host.textContent = '';
|
||||
|
||||
// Create the image element.
|
||||
let img = document.createElement('img');
|
||||
|
||||
// Set the source of the image.
|
||||
img.src = `data:${mimeType};base64,${source}`;
|
||||
|
||||
// Set the size of the image if provided.
|
||||
if (typeof height === 'number') {
|
||||
img.height = height;
|
||||
}
|
||||
if (typeof width === 'number') {
|
||||
img.width = width;
|
||||
}
|
||||
|
||||
if (needsBackground === 'light') {
|
||||
img.classList.add('jp-needs-light-background');
|
||||
} else if (needsBackground === 'dark') {
|
||||
img.classList.add('jp-needs-dark-background');
|
||||
}
|
||||
|
||||
if (unconfined === true) {
|
||||
img.classList.add('jp-mod-unconfined');
|
||||
}
|
||||
|
||||
// Add the image to the host.
|
||||
host.appendChild(img);
|
||||
|
||||
// Return the rendered promise.
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* The namespace for the `renderImage` function statics.
|
||||
*/
|
||||
export namespace renderImage {
|
||||
/**
|
||||
* The options for the `renderImage` function.
|
||||
*/
|
||||
export interface IRenderOptions {
|
||||
/**
|
||||
* The image node to update with the content.
|
||||
*/
|
||||
host: HTMLElement;
|
||||
|
||||
/**
|
||||
* The mime type for the image.
|
||||
*/
|
||||
mimeType: string;
|
||||
|
||||
/**
|
||||
* The base64 encoded source for the image.
|
||||
*/
|
||||
source: string;
|
||||
|
||||
/**
|
||||
* The optional width for the image.
|
||||
*/
|
||||
width?: number;
|
||||
|
||||
/**
|
||||
* The optional height for the image.
|
||||
*/
|
||||
height?: number;
|
||||
|
||||
/**
|
||||
* Whether an image requires a background for legibility.
|
||||
*/
|
||||
needsBackground?: string;
|
||||
|
||||
/**
|
||||
* Whether the image should be unconfined.
|
||||
*/
|
||||
unconfined?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render LaTeX into a host node.
|
||||
*
|
||||
* @params options - The options for rendering.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
export function renderLatex(
|
||||
options: renderLatex.IRenderOptions
|
||||
): Promise<void> {
|
||||
// Unpack the options.
|
||||
let { host, source, shouldTypeset, latexTypesetter } = options;
|
||||
|
||||
// Set the source on the node.
|
||||
host.textContent = source;
|
||||
|
||||
// Typeset the node if needed.
|
||||
if (shouldTypeset && latexTypesetter) {
|
||||
latexTypesetter.typeset(host);
|
||||
}
|
||||
|
||||
// Return the rendered promise.
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* The namespace for the `renderLatex` function statics.
|
||||
*/
|
||||
export namespace renderLatex {
|
||||
/**
|
||||
* The options for the `renderLatex` function.
|
||||
*/
|
||||
export interface IRenderOptions {
|
||||
/**
|
||||
* The host node for the rendered LaTeX.
|
||||
*/
|
||||
host: HTMLElement;
|
||||
|
||||
/**
|
||||
* The LaTeX source to render.
|
||||
*/
|
||||
source: string;
|
||||
|
||||
/**
|
||||
* Whether the node should be typeset.
|
||||
*/
|
||||
shouldTypeset: boolean;
|
||||
|
||||
/**
|
||||
* The LaTeX typesetter for the application.
|
||||
*/
|
||||
latexTypesetter: IRenderMime.ILatexTypesetter | null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render SVG into a host node.
|
||||
*
|
||||
* @params options - The options for rendering.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
export function renderSVG(options: renderSVG.IRenderOptions): Promise<void> {
|
||||
// Unpack the options.
|
||||
let { host, source, trusted, unconfined } = options;
|
||||
|
||||
// Clear the content if there is no source.
|
||||
if (!source) {
|
||||
host.textContent = '';
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// Display a message if the source is not trusted.
|
||||
if (!trusted) {
|
||||
host.textContent =
|
||||
'Cannot display an untrusted SVG. Maybe you need to run the cell?';
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// Render in img so that user can save it easily
|
||||
const img = new Image();
|
||||
img.src = `data:image/svg+xml,${encodeURIComponent(source)}`;
|
||||
host.appendChild(img);
|
||||
|
||||
if (unconfined === true) {
|
||||
host.classList.add('jp-mod-unconfined');
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* The namespace for the `renderSVG` function statics.
|
||||
*/
|
||||
export namespace renderSVG {
|
||||
/**
|
||||
* The options for the `renderSVG` function.
|
||||
*/
|
||||
export interface IRenderOptions {
|
||||
/**
|
||||
* The host node for the rendered SVG.
|
||||
*/
|
||||
host: HTMLElement;
|
||||
|
||||
/**
|
||||
* The SVG source.
|
||||
*/
|
||||
source: string;
|
||||
|
||||
/**
|
||||
* Whether the source is trusted.
|
||||
*/
|
||||
trusted: boolean;
|
||||
|
||||
/**
|
||||
* Whether the svg should be unconfined.
|
||||
*/
|
||||
unconfined?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render text into a host node.
|
||||
*
|
||||
* @params options - The options for rendering.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
export function renderText(options: renderText.IRenderOptions): Promise<void> {
|
||||
// Unpack the options.
|
||||
let { host, source } = options;
|
||||
|
||||
const ansiUp = new AnsiUp();
|
||||
ansiUp.escape_for_html = true;
|
||||
ansiUp.use_classes = true;
|
||||
|
||||
// Create the HTML content.
|
||||
let content = ansiUp.ansi_to_html(source);
|
||||
|
||||
// Set the inner HTML for the host node.
|
||||
host.innerHTML = `<pre>${content}</pre>`;
|
||||
|
||||
// Return the rendered promise.
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* The namespace for the `renderText` function statics.
|
||||
*/
|
||||
export namespace renderText {
|
||||
/**
|
||||
* The options for the `renderText` function.
|
||||
*/
|
||||
export interface IRenderOptions {
|
||||
/**
|
||||
* The host node for the text content.
|
||||
*/
|
||||
host: HTMLElement;
|
||||
|
||||
/**
|
||||
* The source text to render.
|
||||
*/
|
||||
source: string;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The namespace for module implementation details.
|
||||
*/
|
||||
namespace Private {
|
||||
/**
|
||||
* Eval the script tags contained in a host populated by `innerHTML`.
|
||||
*
|
||||
* When script tags are created via `innerHTML`, the browser does not
|
||||
* evaluate them when they are added to the page. This function works
|
||||
* around that by creating new equivalent script nodes manually, and
|
||||
* replacing the originals.
|
||||
*/
|
||||
export function evalInnerHTMLScriptTags(host: HTMLElement): void {
|
||||
// Create a snapshot of the current script nodes.
|
||||
let scripts = host.getElementsByTagName('script');
|
||||
|
||||
// Loop over each script node.
|
||||
for (let i = 0; i < scripts.length; i++) {
|
||||
let script = scripts.item(i);
|
||||
// Skip any scripts which no longer have a parent.
|
||||
if (!script.parentNode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create a new script node which will be clone.
|
||||
let clone = document.createElement('script');
|
||||
|
||||
// Copy the attributes into the clone.
|
||||
let attrs = script.attributes;
|
||||
for (let i = 0, n = attrs.length; i < n; ++i) {
|
||||
let { name, value } = attrs[i];
|
||||
clone.setAttribute(name, value);
|
||||
}
|
||||
|
||||
// Copy the text content into the clone.
|
||||
clone.textContent = script.textContent;
|
||||
|
||||
// Replace the old script in the parent.
|
||||
script.parentNode.replaceChild(clone, script);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the default behavior of nodes.
|
||||
*/
|
||||
export function handleDefaults(
|
||||
node: HTMLElement,
|
||||
resolver?: IRenderMime.IResolver
|
||||
): void {
|
||||
// Handle anchor elements.
|
||||
let anchors = node.getElementsByTagName('a');
|
||||
for (let i = 0; i < anchors.length; i++) {
|
||||
let path = anchors[i].href || '';
|
||||
const isLocal =
|
||||
resolver && resolver.isLocal
|
||||
? resolver.isLocal(path)
|
||||
: URLExt.isLocal(path);
|
||||
if (isLocal) {
|
||||
anchors[i].target = '_self';
|
||||
} else {
|
||||
anchors[i].target = '_blank';
|
||||
}
|
||||
}
|
||||
|
||||
// Handle image elements.
|
||||
let imgs = node.getElementsByTagName('img');
|
||||
for (let i = 0; i < imgs.length; i++) {
|
||||
if (!imgs[i].alt) {
|
||||
imgs[i].alt = 'Image';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the relative urls in element `src` and `href` attributes.
|
||||
*
|
||||
* @param node - The head html element.
|
||||
*
|
||||
* @param resolver - A url resolver.
|
||||
*
|
||||
* @param linkHandler - An optional link handler for nodes.
|
||||
*
|
||||
* @returns a promise fulfilled when the relative urls have been resolved.
|
||||
*/
|
||||
export function handleUrls(
|
||||
node: HTMLElement,
|
||||
resolver: IRenderMime.IResolver,
|
||||
linkHandler: IRenderMime.ILinkHandler | null
|
||||
): Promise<void> {
|
||||
// Set up an array to collect promises.
|
||||
let promises: Promise<void>[] = [];
|
||||
|
||||
// Handle HTML Elements with src attributes.
|
||||
let nodes = node.querySelectorAll('*[src]');
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
promises.push(handleAttr(nodes[i] as HTMLElement, 'src', resolver));
|
||||
}
|
||||
|
||||
// Handle anchor elements.
|
||||
let anchors = node.getElementsByTagName('a');
|
||||
for (let i = 0; i < anchors.length; i++) {
|
||||
promises.push(handleAnchor(anchors[i], resolver, linkHandler));
|
||||
}
|
||||
|
||||
// Handle link elements.
|
||||
let links = node.getElementsByTagName('link');
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
promises.push(handleAttr(links[i], 'href', resolver));
|
||||
}
|
||||
|
||||
// Wait on all promises.
|
||||
return Promise.all(promises).then(() => undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply ids to headers.
|
||||
*/
|
||||
export function headerAnchors(node: HTMLElement): void {
|
||||
let headerNames = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
|
||||
for (let headerType of headerNames) {
|
||||
let headers = node.getElementsByTagName(headerType);
|
||||
for (let i = 0; i < headers.length; i++) {
|
||||
let header = headers[i];
|
||||
header.id = encodeURIComponent(header.innerHTML.replace(/ /g, '-'));
|
||||
let anchor = document.createElement('a');
|
||||
anchor.target = '_self';
|
||||
anchor.textContent = '¶';
|
||||
anchor.href = '#' + header.id;
|
||||
anchor.classList.add('jp-InternalAnchorLink');
|
||||
header.appendChild(anchor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a node with a `src` or `href` attribute.
|
||||
*/
|
||||
function handleAttr(
|
||||
node: HTMLElement,
|
||||
name: 'src' | 'href',
|
||||
resolver: IRenderMime.IResolver
|
||||
): Promise<void> {
|
||||
let source = node.getAttribute(name) || '';
|
||||
const isLocal = resolver.isLocal
|
||||
? resolver.isLocal(source)
|
||||
: URLExt.isLocal(source);
|
||||
if (!source || !isLocal) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
node.setAttribute(name, '');
|
||||
return resolver
|
||||
.resolveUrl(source)
|
||||
.then(path => {
|
||||
return resolver.getDownloadUrl(path);
|
||||
})
|
||||
.then(url => {
|
||||
// Check protocol again in case it changed:
|
||||
if (URI.parse(url).scheme !== 'data:') {
|
||||
// Bust caching for local src attrs.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache
|
||||
url += (/\?/.test(url) ? '&' : '?') + new Date().getTime();
|
||||
}
|
||||
node.setAttribute(name, url);
|
||||
})
|
||||
.catch(err => {
|
||||
// If there was an error getting the url,
|
||||
// just make it an empty link.
|
||||
node.setAttribute(name, '');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an anchor node.
|
||||
*/
|
||||
function handleAnchor(
|
||||
anchor: HTMLAnchorElement,
|
||||
resolver: IRenderMime.IResolver,
|
||||
linkHandler: IRenderMime.ILinkHandler | null
|
||||
): Promise<void> {
|
||||
// Get the link path without the location prepended.
|
||||
// (e.g. "./foo.md#Header 1" vs "http://localhost:8888/foo.md#Header 1")
|
||||
let href = anchor.getAttribute('href') || '';
|
||||
const isLocal = resolver.isLocal
|
||||
? resolver.isLocal(href)
|
||||
: URLExt.isLocal(href);
|
||||
// Bail if it is not a file-like url.
|
||||
if (!href || !isLocal) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
// Remove the hash until we can handle it.
|
||||
let hash = anchor.hash;
|
||||
if (hash) {
|
||||
// Handle internal link in the file.
|
||||
if (hash === href) {
|
||||
anchor.target = '_self';
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
// For external links, remove the hash until we have hash handling.
|
||||
href = href.replace(hash, '');
|
||||
}
|
||||
// Get the appropriate file path.
|
||||
return resolver
|
||||
.resolveUrl(href)
|
||||
.then(path => {
|
||||
// Handle the click override.
|
||||
if (linkHandler) {
|
||||
linkHandler.handleLink(anchor, path, hash);
|
||||
}
|
||||
// Get the appropriate file download path.
|
||||
return resolver.getDownloadUrl(path);
|
||||
})
|
||||
.then(url => {
|
||||
// Set the visible anchor.
|
||||
anchor.href = url + hash;
|
||||
})
|
||||
.catch(err => {
|
||||
// If there was an error getting the url,
|
||||
// just make it an empty link.
|
||||
anchor.href = '';
|
||||
});
|
||||
}
|
||||
}
|
||||
1053
src/sql/parts/notebook/outputs/sanitizer.ts
Normal file
1053
src/sql/parts/notebook/outputs/sanitizer.ts
Normal file
File diff suppressed because it is too large
Load Diff
467
src/sql/parts/notebook/outputs/style/index.css
Normal file
467
src/sql/parts/notebook/outputs/style/index.css
Normal file
@@ -0,0 +1,467 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
| Copyright (c) Jupyter Development Team.
|
||||
| Distributed under the terms of the Modified BSD License.
|
||||
|----------------------------------------------------------------------------*/
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
| RenderedText
|
||||
|----------------------------------------------------------------------------*/
|
||||
|
||||
output-component .jp-RenderedText {
|
||||
text-align: left;
|
||||
padding-left: var(--jp-code-padding);
|
||||
font-size: var(--jp-code-font-size);
|
||||
line-height: var(--jp-code-line-height);
|
||||
font-family: var(--jp-code-font-family);
|
||||
}
|
||||
|
||||
output-component .jp-RenderedText pre,
|
||||
.jp-RenderedJavaScript pre,
|
||||
output-component .jp-RenderedHTMLCommon pre {
|
||||
color: var(--jp-content-font-color1);
|
||||
border: none;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
/* ansi_up creates classed spans for console foregrounds and backgrounds. */
|
||||
output-component .jp-RenderedText pre .ansi-black-fg {
|
||||
color: #3e424d;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-red-fg {
|
||||
color: #e75c58;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-green-fg {
|
||||
color: #00a250;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-yellow-fg {
|
||||
color: #ddb62b;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-blue-fg {
|
||||
color: #208ffb;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-magenta-fg {
|
||||
color: #d160c4;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-cyan-fg {
|
||||
color: #60c6c8;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-white-fg {
|
||||
color: #c5c1b4;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedText pre .ansi-black-bg {
|
||||
background-color: #3e424d;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-red-bg {
|
||||
background-color: #e75c58;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-green-bg {
|
||||
background-color: #00a250;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-yellow-bg {
|
||||
background-color: #ddb62b;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-blue-bg {
|
||||
background-color: #208ffb;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-magenta-bg {
|
||||
background-color: #d160c4;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-cyan-bg {
|
||||
background-color: #60c6c8;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-white-bg {
|
||||
background-color: #c5c1b4;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedText pre .ansi-bright-black-fg {
|
||||
color: #282c36;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-red-fg {
|
||||
color: #b22b31;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-green-fg {
|
||||
color: #007427;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-yellow-fg {
|
||||
color: #b27d12;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-blue-fg {
|
||||
color: #0065ca;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-magenta-fg {
|
||||
color: #a03196;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-cyan-fg {
|
||||
color: #258f8f;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-white-fg {
|
||||
color: #a1a6b2;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedText pre .ansi-bright-black-bg {
|
||||
background-color: #282c36;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-red-bg {
|
||||
background-color: #b22b31;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-green-bg {
|
||||
background-color: #007427;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-yellow-bg {
|
||||
background-color: #b27d12;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-blue-bg {
|
||||
background-color: #0065ca;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-magenta-bg {
|
||||
background-color: #a03196;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-cyan-bg {
|
||||
background-color: #258f8f;
|
||||
}
|
||||
output-component .jp-RenderedText pre .ansi-bright-white-bg {
|
||||
background-color: #a1a6b2;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedText[data-mime-type='application/vnd.jupyter.stderr'] {
|
||||
background: var(--jp-rendermime-error-background);
|
||||
padding-top: var(--jp-code-padding);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
| RenderedLatex
|
||||
|----------------------------------------------------------------------------*/
|
||||
|
||||
.jp-RenderedLatex {
|
||||
color: var(--jp-content-font-color1);
|
||||
font-size: var(--jp-content-font-size1);
|
||||
line-height: var(--jp-content-line-height);
|
||||
}
|
||||
|
||||
/* Left-justify outputs.*/
|
||||
.jp-OutputArea-output.jp-RenderedLatex {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
| RenderedHTML
|
||||
|----------------------------------------------------------------------------*/
|
||||
|
||||
output-component .jp-RenderedHTMLCommon {
|
||||
color: var(--jp-content-font-color1);
|
||||
font-family: var(--jp-content-font-family);
|
||||
font-size: var(--jp-content-font-size1);
|
||||
line-height: var(--jp-content-line-height);
|
||||
/* Give a bit more R padding on Markdown text to keep line lengths reasonable */
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon em {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon u {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon a:link {
|
||||
text-decoration: none;
|
||||
color: var(--jp-content-link-color);
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon a:hover {
|
||||
text-decoration: underline;
|
||||
color: var(--jp-content-link-color);
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon a:visited {
|
||||
text-decoration: none;
|
||||
color: var(--jp-content-link-color);
|
||||
}
|
||||
|
||||
/* Headings */
|
||||
|
||||
output-component .jp-RenderedHTMLCommon h1,
|
||||
output-component .jp-RenderedHTMLCommon h2,
|
||||
output-component .jp-RenderedHTMLCommon h3,
|
||||
output-component .jp-RenderedHTMLCommon h4,
|
||||
output-component .jp-RenderedHTMLCommon h5,
|
||||
output-component .jp-RenderedHTMLCommon h6 {
|
||||
line-height: var(--jp-content-heading-line-height);
|
||||
font-weight: var(--jp-content-heading-font-weight);
|
||||
font-style: normal;
|
||||
margin: var(--jp-content-heading-margin-top) 0
|
||||
var(--jp-content-heading-margin-bottom) 0;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon h1:first-child,
|
||||
output-component .jp-RenderedHTMLCommon h2:first-child,
|
||||
output-component .jp-RenderedHTMLCommon h3:first-child,
|
||||
output-component .jp-RenderedHTMLCommon h4:first-child,
|
||||
output-component .jp-RenderedHTMLCommon h5:first-child,
|
||||
output-component .jp-RenderedHTMLCommon h6:first-child {
|
||||
margin-top: calc(0.5 * var(--jp-content-heading-margin-top));
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon h1:last-child,
|
||||
output-component .jp-RenderedHTMLCommon h2:last-child,
|
||||
output-component .jp-RenderedHTMLCommon h3:last-child,
|
||||
output-component .jp-RenderedHTMLCommon h4:last-child,
|
||||
output-component .jp-RenderedHTMLCommon h5:last-child,
|
||||
output-component .jp-RenderedHTMLCommon h6:last-child {
|
||||
margin-bottom: calc(0.5 * var(--jp-content-heading-margin-bottom));
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon h1 {
|
||||
font-size: var(--jp-content-font-size5);
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon h2 {
|
||||
font-size: var(--jp-content-font-size4);
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon h3 {
|
||||
font-size: var(--jp-content-font-size3);
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon h4 {
|
||||
font-size: var(--jp-content-font-size2);
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon h5 {
|
||||
font-size: var(--jp-content-font-size1);
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon h6 {
|
||||
font-size: var(--jp-content-font-size0);
|
||||
}
|
||||
|
||||
/* Lists */
|
||||
|
||||
output-component .jp-RenderedHTMLCommon ul:not(.list-inline),
|
||||
output-component .jp-RenderedHTMLCommon ol:not(.list-inline) {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon ul {
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon ul ul {
|
||||
list-style: square;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon ul ul ul {
|
||||
list-style: circle;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon ol {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon ol ol {
|
||||
list-style: upper-alpha;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon ol ol ol {
|
||||
list-style: lower-alpha;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon ol ol ol ol {
|
||||
list-style: lower-roman;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon ol ol ol ol ol {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon ol,
|
||||
output-component .jp-RenderedHTMLCommon ul {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon ul ul,
|
||||
output-component .jp-RenderedHTMLCommon ul ol,
|
||||
output-component .jp-RenderedHTMLCommon ol ul,
|
||||
output-component .jp-RenderedHTMLCommon ol ol {
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon hr {
|
||||
color: var(--jp-border-color2);
|
||||
background-color: var(--jp-border-color1);
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon > pre {
|
||||
margin: 1.5em 2em;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon pre,
|
||||
output-component .jp-RenderedHTMLCommon code {
|
||||
border: 0;
|
||||
background-color: var(--jp-layout-color0);
|
||||
color: var(--jp-content-font-color1);
|
||||
font-family: var(--jp-code-font-family);
|
||||
font-size: inherit;
|
||||
line-height: var(--jp-code-line-height);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon p > code {
|
||||
background-color: var(--jp-layout-color2);
|
||||
padding: 1px 5px;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
|
||||
output-component .jp-RenderedHTMLCommon table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
border: none;
|
||||
color: var(--jp-ui-font-color1);
|
||||
font-size: 12px;
|
||||
table-layout: fixed;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon thead {
|
||||
border-bottom: var(--jp-border-width) solid var(--jp-border-color1);
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon td,
|
||||
output-component .jp-RenderedHTMLCommon th,
|
||||
output-component .jp-RenderedHTMLCommon tr {
|
||||
text-align: right;
|
||||
vertical-align: middle;
|
||||
padding: 0.5em 0.5em;
|
||||
line-height: normal;
|
||||
white-space: normal;
|
||||
max-width: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.jp-RenderedMarkdown.jp-RenderedHTMLCommon td,
|
||||
.jp-RenderedMarkdown.jp-RenderedHTMLCommon th {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
output-component th {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon tbody tr:nth-child(odd) {
|
||||
background: var(--jp-layout-color0);
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon tbody tr:nth-child(even) {
|
||||
background: var(--jp-rendermime-table-row-background);
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon tbody tr:hover {
|
||||
background: var(--jp-rendermime-table-row-hover-background);
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon table {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon p {
|
||||
text-align: left;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon p {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon img {
|
||||
-moz-force-broken-image-icon: 1;
|
||||
}
|
||||
|
||||
/* Restrict to direct children as other images could be nested in other content. */
|
||||
output-component .jp-RenderedHTMLCommon > img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
/* Change color behind transparent images if they need it... */
|
||||
[data-theme-light='false'] .jp-RenderedImage img.jp-needs-light-background {
|
||||
background-color: var(--jp-inverse-layout-color1);
|
||||
}
|
||||
[data-theme-light='true'] .jp-RenderedImage img.jp-needs-dark-background {
|
||||
background-color: var(--jp-inverse-layout-color1);
|
||||
}
|
||||
/* ...or leave it untouched if they don't */
|
||||
[data-theme-light='false'] .jp-RenderedImage img.jp-needs-dark-background {
|
||||
}
|
||||
[data-theme-light='true'] .jp-RenderedImage img.jp-needs-light-background {
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon img,
|
||||
.jp-RenderedImage img,
|
||||
output-component .jp-RenderedHTMLCommon svg,
|
||||
.jp-RenderedSVG svg {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon img.jp-mod-unconfined,
|
||||
.jp-RenderedImage img.jp-mod-unconfined,
|
||||
output-component .jp-RenderedHTMLCommon svg.jp-mod-unconfined,
|
||||
.jp-RenderedSVG svg.jp-mod-unconfined {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon .alert {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
output-component .jp-RenderedHTMLCommon blockquote {
|
||||
margin: 1em 2em;
|
||||
padding: 0 1em;
|
||||
border-left: 5px solid var(--jp-border-color2);
|
||||
}
|
||||
|
||||
a.jp-InternalAnchorLink {
|
||||
visibility: hidden;
|
||||
margin-left: 8px;
|
||||
color: var(--md-blue-800);
|
||||
}
|
||||
|
||||
h1:hover .jp-InternalAnchorLink,
|
||||
h2:hover .jp-InternalAnchorLink,
|
||||
h3:hover .jp-InternalAnchorLink,
|
||||
h4:hover .jp-InternalAnchorLink,
|
||||
h5:hover .jp-InternalAnchorLink,
|
||||
h6:hover .jp-InternalAnchorLink {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* Most direct children of .jp-RenderedHTMLCommon have a margin-bottom of 1.0.
|
||||
* At the bottom of cells this is a bit too much as there is also spacing
|
||||
* between cells. Going all the way to 0 gets too tight between markdown and
|
||||
* code cells.
|
||||
*/
|
||||
output-component .jp-RenderedHTMLCommon > *:last-child {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
| RenderedPDF
|
||||
|----------------------------------------------------------------------------*/
|
||||
|
||||
.jp-RenderedPDF {
|
||||
font-size: var(--jp-ui-font-size1);
|
||||
}
|
||||
348
src/sql/parts/notebook/outputs/widgets.ts
Normal file
348
src/sql/parts/notebook/outputs/widgets.ts
Normal file
@@ -0,0 +1,348 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import * as renderers from './renderers';
|
||||
import { IRenderMime } from './common/renderMimeInterfaces';
|
||||
import { ReadonlyJSONObject } from './common/jsonext';
|
||||
|
||||
/**
|
||||
* A common base class for mime renderers.
|
||||
*/
|
||||
export abstract class RenderedCommon implements IRenderMime.IRenderer {
|
||||
private _node: HTMLElement;
|
||||
private cachedClasses: string[] = [];
|
||||
/**
|
||||
* Construct a new rendered common widget.
|
||||
*
|
||||
* @param options - The options for initializing the widget.
|
||||
*/
|
||||
constructor(options: IRenderMime.IRendererOptions) {
|
||||
this.mimeType = options.mimeType;
|
||||
this.sanitizer = options.sanitizer;
|
||||
this.resolver = options.resolver;
|
||||
this.linkHandler = options.linkHandler;
|
||||
this.latexTypesetter = options.latexTypesetter;
|
||||
}
|
||||
|
||||
public get node(): HTMLElement {
|
||||
return this._node;
|
||||
}
|
||||
|
||||
public set node(value: HTMLElement) {
|
||||
this._node = value;
|
||||
value.dataset['mimeType'] = this.mimeType;
|
||||
this._node.classList.add(...this.cachedClasses);
|
||||
this.cachedClasses = [];
|
||||
}
|
||||
|
||||
toggleClass(className: string, enabled: boolean): void {
|
||||
if (enabled) {
|
||||
this.addClass(className);
|
||||
} else {
|
||||
this.removeClass(className);
|
||||
}
|
||||
}
|
||||
|
||||
addClass(className: string): void {
|
||||
if (!this._node) {
|
||||
this.cachedClasses.push(className);
|
||||
} else if (!this._node.classList.contains(className)) {
|
||||
this._node.classList.add(className);
|
||||
}
|
||||
}
|
||||
|
||||
removeClass(className: string): void {
|
||||
if (!this._node) {
|
||||
this.cachedClasses = this.cachedClasses.filter(c => c !== className);
|
||||
} else if (this._node.classList.contains(className)) {
|
||||
this._node.classList.remove(className);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The mimetype being rendered.
|
||||
*/
|
||||
readonly mimeType: string;
|
||||
|
||||
/**
|
||||
* The sanitizer used to sanitize untrusted html inputs.
|
||||
*/
|
||||
readonly sanitizer: IRenderMime.ISanitizer;
|
||||
|
||||
/**
|
||||
* The resolver object.
|
||||
*/
|
||||
readonly resolver: IRenderMime.IResolver | null;
|
||||
|
||||
/**
|
||||
* The link handler.
|
||||
*/
|
||||
readonly linkHandler: IRenderMime.ILinkHandler | null;
|
||||
|
||||
/**
|
||||
* The latexTypesetter.
|
||||
*/
|
||||
readonly latexTypesetter: IRenderMime.ILatexTypesetter;
|
||||
|
||||
/**
|
||||
* Render a mime model.
|
||||
*
|
||||
* @param model - The mime model to render.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
renderModel(model: IRenderMime.IMimeModel): Promise<void> {
|
||||
// TODO compare model against old model for early bail?
|
||||
|
||||
// Toggle the trusted class on the widget.
|
||||
this.toggleClass('jp-mod-trusted', model.trusted);
|
||||
|
||||
// Render the actual content.
|
||||
return this.render(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the mime model.
|
||||
*
|
||||
* @param model - The mime model to render.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
abstract render(model: IRenderMime.IMimeModel): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A common base class for HTML mime renderers.
|
||||
*/
|
||||
export abstract class RenderedHTMLCommon extends RenderedCommon {
|
||||
/**
|
||||
* Construct a new rendered HTML common widget.
|
||||
*
|
||||
* @param options - The options for initializing the widget.
|
||||
*/
|
||||
constructor(options: IRenderMime.IRendererOptions) {
|
||||
super(options);
|
||||
this.addClass('jp-RenderedHTMLCommon');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A mime renderer for displaying HTML and math.
|
||||
*/
|
||||
export class RenderedHTML extends RenderedHTMLCommon {
|
||||
/**
|
||||
* Construct a new rendered HTML widget.
|
||||
*
|
||||
* @param options - The options for initializing the widget.
|
||||
*/
|
||||
constructor(options: IRenderMime.IRendererOptions) {
|
||||
super(options);
|
||||
this.addClass('jp-RenderedHTML');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a mime model.
|
||||
*
|
||||
* @param model - The mime model to render.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
render(model: IRenderMime.IMimeModel): Promise<void> {
|
||||
return renderers.renderHTML({
|
||||
host: this.node,
|
||||
source: String(model.data[this.mimeType]),
|
||||
trusted: model.trusted,
|
||||
resolver: this.resolver,
|
||||
sanitizer: this.sanitizer,
|
||||
linkHandler: this.linkHandler,
|
||||
shouldTypeset: true, //this.isAttached,
|
||||
latexTypesetter: this.latexTypesetter
|
||||
});
|
||||
}
|
||||
|
||||
// /**
|
||||
// * A message handler invoked on an `'after-attach'` message.
|
||||
// */
|
||||
// onAfterAttach(msg: Message): void {
|
||||
// if (this.latexTypesetter) {
|
||||
// this.latexTypesetter.typeset(this.node);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// /**
|
||||
// * A mime renderer for displaying LaTeX output.
|
||||
// */
|
||||
// export class RenderedLatex extends RenderedCommon {
|
||||
// /**
|
||||
// * Construct a new rendered LaTeX widget.
|
||||
// *
|
||||
// * @param options - The options for initializing the widget.
|
||||
// */
|
||||
// constructor(options: IRenderMime.IRendererOptions) {
|
||||
// super(options);
|
||||
// this.addClass('jp-RenderedLatex');
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Render a mime model.
|
||||
// *
|
||||
// * @param model - The mime model to render.
|
||||
// *
|
||||
// * @returns A promise which resolves when rendering is complete.
|
||||
// */
|
||||
// render(model: IRenderMime.IMimeModel): Promise<void> {
|
||||
// return renderers.renderLatex({
|
||||
// host: this.node,
|
||||
// source: String(model.data[this.mimeType]),
|
||||
// shouldTypeset: this.isAttached,
|
||||
// latexTypesetter: this.latexTypesetter
|
||||
// });
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * A message handler invoked on an `'after-attach'` message.
|
||||
// */
|
||||
// onAfterAttach(msg: Message): void {
|
||||
// if (this.latexTypesetter) {
|
||||
// this.latexTypesetter.typeset(this.node);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* A mime renderer for displaying images.
|
||||
*/
|
||||
export class RenderedImage extends RenderedCommon {
|
||||
/**
|
||||
* Construct a new rendered image widget.
|
||||
*
|
||||
* @param options - The options for initializing the widget.
|
||||
*/
|
||||
constructor(options: IRenderMime.IRendererOptions) {
|
||||
super(options);
|
||||
this.addClass('jp-RenderedImage');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a mime model.
|
||||
*
|
||||
* @param model - The mime model to render.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
render(model: IRenderMime.IMimeModel): Promise<void> {
|
||||
let metadata = model.metadata[this.mimeType] as ReadonlyJSONObject;
|
||||
return renderers.renderImage({
|
||||
host: this.node,
|
||||
mimeType: this.mimeType,
|
||||
source: String(model.data[this.mimeType]),
|
||||
width: metadata && (metadata.width as number | undefined),
|
||||
height: metadata && (metadata.height as number | undefined),
|
||||
needsBackground: model.metadata['needs_background'] as string | undefined,
|
||||
unconfined: metadata && (metadata.unconfined as boolean | undefined)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A widget for displaying SVG content.
|
||||
*/
|
||||
export class RenderedSVG extends RenderedCommon {
|
||||
/**
|
||||
* Construct a new rendered SVG widget.
|
||||
*
|
||||
* @param options - The options for initializing the widget.
|
||||
*/
|
||||
constructor(options: IRenderMime.IRendererOptions) {
|
||||
super(options);
|
||||
this.addClass('jp-RenderedSVG');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a mime model.
|
||||
*
|
||||
* @param model - The mime model to render.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
render(model: IRenderMime.IMimeModel): Promise<void> {
|
||||
let metadata = model.metadata[this.mimeType] as ReadonlyJSONObject;
|
||||
return renderers.renderSVG({
|
||||
host: this.node,
|
||||
source: String(model.data[this.mimeType]),
|
||||
trusted: model.trusted,
|
||||
unconfined: metadata && (metadata.unconfined as boolean | undefined)
|
||||
});
|
||||
}
|
||||
|
||||
// /**
|
||||
// * A message handler invoked on an `'after-attach'` message.
|
||||
// */
|
||||
// onAfterAttach(msg: Message): void {
|
||||
// if (this.latexTypesetter) {
|
||||
// this.latexTypesetter.typeset(this.node);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* A widget for displaying plain text and console text.
|
||||
*/
|
||||
export class RenderedText extends RenderedCommon {
|
||||
/**
|
||||
* Construct a new rendered text widget.
|
||||
*
|
||||
* @param options - The options for initializing the widget.
|
||||
*/
|
||||
constructor(options: IRenderMime.IRendererOptions) {
|
||||
super(options);
|
||||
this.addClass('jp-RenderedText');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a mime model.
|
||||
*
|
||||
* @param model - The mime model to render.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
render(model: IRenderMime.IMimeModel): Promise<void> {
|
||||
return renderers.renderText({
|
||||
host: this.node,
|
||||
source: String(model.data[this.mimeType])
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A widget for displaying deprecated JavaScript output.
|
||||
*/
|
||||
export class RenderedJavaScript extends RenderedCommon {
|
||||
/**
|
||||
* Construct a new rendered text widget.
|
||||
*
|
||||
* @param options - The options for initializing the widget.
|
||||
*/
|
||||
constructor(options: IRenderMime.IRendererOptions) {
|
||||
super(options);
|
||||
this.addClass('jp-RenderedJavaScript');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a mime model.
|
||||
*
|
||||
* @param model - The mime model to render.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
render(model: IRenderMime.IMimeModel): Promise<void> {
|
||||
return renderers.renderText({
|
||||
host: this.node,
|
||||
source: 'JavaScript output is disabled in Notebooks'
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import * as sqlops from 'sqlops';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { RenderMimeRegistry } from 'sql/parts/notebook/outputs/registry';
|
||||
import { ModelFactory } from 'sql/parts/notebook/models/modelFactory';
|
||||
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
|
||||
|
||||
@@ -40,6 +41,8 @@ export interface INotebookService {
|
||||
getOrCreateNotebookManager(providerId: string, uri: URI): Thenable<INotebookManager>;
|
||||
|
||||
shutdown(): void;
|
||||
|
||||
getMimeRegistry(): RenderMimeRegistry;
|
||||
}
|
||||
|
||||
export interface INotebookProvider {
|
||||
|
||||
@@ -9,17 +9,21 @@ import { nb } from 'sqlops';
|
||||
import * as nls from 'vs/nls';
|
||||
import { INotebookService, INotebookManager, INotebookProvider, DEFAULT_NOTEBOOK_PROVIDER } from 'sql/services/notebook/notebookService';
|
||||
import URI from 'vs/base/common/uri';
|
||||
import { RenderMimeRegistry } from 'sql/parts/notebook/outputs/registry';
|
||||
import { standardRendererFactories } from 'sql/parts/notebook/outputs/factories';
|
||||
import { LocalContentManager } from 'sql/services/notebook/localContentManager';
|
||||
import { session } from 'electron';
|
||||
import { SessionManager } from 'sql/services/notebook/sessionManager';
|
||||
|
||||
export class NotebookService implements INotebookService {
|
||||
_serviceBrand: any;
|
||||
|
||||
private _mimeRegistry: RenderMimeRegistry;
|
||||
private _providers: Map<string, INotebookProvider> = new Map();
|
||||
private _managers: Map<URI, INotebookManager> = new Map();
|
||||
|
||||
|
||||
constructor() {
|
||||
mimeRegistry: RenderMimeRegistry;
|
||||
let defaultProvider = new BuiltinProvider();
|
||||
this.registerProvider(defaultProvider.providerId, defaultProvider);
|
||||
}
|
||||
@@ -65,6 +69,18 @@ export class NotebookService implements INotebookService {
|
||||
|
||||
return op(provider);
|
||||
}
|
||||
|
||||
//Returns an instantiation of RenderMimeRegistry class
|
||||
getMimeRegistry(): RenderMimeRegistry {
|
||||
if (!this._mimeRegistry) {
|
||||
return new RenderMimeRegistry({
|
||||
initialFactories: standardRendererFactories
|
||||
});
|
||||
}
|
||||
return this._mimeRegistry;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export class BuiltinProvider implements INotebookProvider {
|
||||
|
||||
Reference in New Issue
Block a user