jupyterlab-emrys
Version:
A computational environment for Jupyter. Powered by Emrys
485 lines (484 loc) • 14.3 kB
JavaScript
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
;
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var CodeMirror = require('codemirror');
require('codemirror/addon/runmode/runmode');
var marked = require('marked');
var ansi_up_1 = require('ansi_up');
var phosphor_widget_1 = require('phosphor-widget');
var codemirror_1 = require('../codemirror');
var latex_1 = require('./latex');
/**
* The class name added to rendered widgets.
*/
var RENDERED_CLASS = 'jp-Rendered';
/**
* The class name added to rendered html widgets.
*/
var RENDERED_HTML = 'jp-Rendered-html';
// Support GitHub flavored Markdown, leave sanitizing to external library.
marked.setOptions({
gfm: true,
sanitize: false,
breaks: true,
langPrefix: 'cm-s-default language-',
highlight: function (code, lang, callback) {
if (!lang) {
// no language, no highlight
if (callback) {
callback(null, code);
return;
}
else {
return code;
}
}
codemirror_1.requireMode(lang).then(function (spec) {
var el = document.createElement('div');
if (!spec) {
console.log("No CodeMirror mode: " + lang);
callback(null, code);
return;
}
try {
CodeMirror.runMode(code, spec.mime, el);
callback(null, el.innerHTML);
}
catch (err) {
console.log("Failed to highlight " + lang + " code", err);
callback(err, code);
}
}).catch(function (err) {
console.log("No CodeMirror mode: " + lang);
console.log("Require CodeMirror mode error: " + err);
callback(null, code);
});
}
});
/**
* A widget for displaying HTML and rendering math.
*/
var HTMLWidget = (function (_super) {
__extends(HTMLWidget, _super);
/**
* Construct a new html widget.
*/
function HTMLWidget(options) {
_super.call(this);
this.addClass(RENDERED_HTML);
this.addClass(RENDERED_CLASS);
var source = options.source;
if (options.sanitizer) {
source = options.sanitizer.sanitize(source);
}
appendHtml(this.node, source);
if (options.resolver) {
resolveUrls(this.node, options.resolver);
}
}
/**
* A message handler invoked on an `'after-attach'` message.
*/
HTMLWidget.prototype.onAfterAttach = function (msg) {
latex_1.typeset(this.node);
};
return HTMLWidget;
}(phosphor_widget_1.Widget));
/**
* A widget for displaying Markdown.
*/
var MarkdownWidget = (function (_super) {
__extends(MarkdownWidget, _super);
/**
* Construct a new markdown widget.
*/
function MarkdownWidget(options) {
var _this = this;
_super.call(this);
this._rendered = false;
this.addClass(RENDERED_HTML);
this.addClass(RENDERED_CLASS);
var parts = latex_1.removeMath(options.source);
// Add the markdown content asynchronously.
marked(parts['text'], function (err, content) {
if (err) {
console.error(err);
return;
}
content = latex_1.replaceMath(content, parts['math']);
if (options.sanitizer) {
content = options.sanitizer.sanitize(content);
}
appendHtml(_this.node, content);
if (options.resolver) {
resolveUrls(_this.node, options.resolver);
}
_this.fit();
_this._rendered = true;
if (_this.isAttached) {
latex_1.typeset(_this.node);
}
});
}
/**
* A message handler invoked on an `'after-attach'` message.
*/
MarkdownWidget.prototype.onAfterAttach = function (msg) {
if (this._rendered) {
latex_1.typeset(this.node);
}
};
return MarkdownWidget;
}(phosphor_widget_1.Widget));
/**
* A widget for displaying LaTeX output.
*/
var LatexWidget = (function (_super) {
__extends(LatexWidget, _super);
/**
* Construct a new latex widget.
*/
function LatexWidget(text) {
_super.call(this);
this.node.textContent = text;
this.addClass(RENDERED_CLASS);
}
/**
* A message handler invoked on an `'after-attach'` message.
*/
LatexWidget.prototype.onAfterAttach = function (msg) {
latex_1.typeset(this.node);
};
return LatexWidget;
}(phosphor_widget_1.Widget));
/**
* A renderer for raw html.
*/
var HTMLRenderer = (function () {
function HTMLRenderer() {
/**
* The mimetypes this renderer accepts.
*/
this.mimetypes = ['text/html'];
}
/**
* Whether the input can safely sanitized for a given mimetype.
*/
HTMLRenderer.prototype.sanitizable = function (mimetype) {
return this.mimetypes.indexOf(mimetype) !== -1;
};
/**
* Whether the input is safe without sanitization.
*/
HTMLRenderer.prototype.isSafe = function (mimetype) {
return false;
};
/**
* Render the transformed mime bundle.
*/
HTMLRenderer.prototype.render = function (options) {
return new HTMLWidget(options);
};
return HTMLRenderer;
}());
exports.HTMLRenderer = HTMLRenderer;
/**
* A renderer for `<img>` data.
*/
var ImageRenderer = (function () {
function ImageRenderer() {
/**
* The mimetypes this renderer accepts.
*/
this.mimetypes = ['image/png', 'image/jpeg', 'image/gif'];
}
/**
* Whether the input can safely sanitized for a given mimetype.
*/
ImageRenderer.prototype.sanitizable = function (mimetype) {
return false;
};
/**
* Whether the input is safe without sanitization.
*/
ImageRenderer.prototype.isSafe = function (mimetype) {
return this.mimetypes.indexOf(mimetype) !== -1;
};
/**
* Render the transformed mime bundle.
*/
ImageRenderer.prototype.render = function (options) {
var w = new phosphor_widget_1.Widget();
var img = document.createElement('img');
img.src = "data:" + options.mimetype + ";base64," + options.source;
w.node.appendChild(img);
w.addClass(RENDERED_CLASS);
return w;
};
return ImageRenderer;
}());
exports.ImageRenderer = ImageRenderer;
/**
* A renderer for plain text and Jupyter console text data.
*/
var TextRenderer = (function () {
function TextRenderer() {
/**
* The mimetypes this renderer accepts.
*/
this.mimetypes = ['text/plain', 'application/vnd.jupyter.console-text'];
}
/**
* Whether the input can safely sanitized for a given mimetype.
*/
TextRenderer.prototype.sanitizable = function (mimetype) {
return false;
};
/**
* Whether the input is safe without sanitization.
*/
TextRenderer.prototype.isSafe = function (mimetype) {
return this.mimetypes.indexOf(mimetype) !== -1;
};
/**
* Render the transformed mime bundle.
*/
TextRenderer.prototype.render = function (options) {
var w = new phosphor_widget_1.Widget();
var data = ansi_up_1.escape_for_html(options.source);
var pre = document.createElement('pre');
pre.innerHTML = ansi_up_1.ansi_to_html(data);
w.node.appendChild(pre);
w.addClass(RENDERED_CLASS);
return w;
};
return TextRenderer;
}());
exports.TextRenderer = TextRenderer;
/**
* A renderer for raw `<script>` data.
*/
var JavascriptRenderer = (function () {
function JavascriptRenderer() {
/**
* The mimetypes this renderer accepts.
*/
this.mimetypes = ['text/javascript', 'application/javascript'];
}
/**
* Whether the input can safely sanitized for a given mimetype.
*/
JavascriptRenderer.prototype.sanitizable = function (mimetype) {
return false;
};
/**
* Whether the input is safe without sanitization.
*/
JavascriptRenderer.prototype.isSafe = function (mimetype) {
return false;
};
/**
* Render the transformed mime bundle.
*/
JavascriptRenderer.prototype.render = function (options) {
var w = new phosphor_widget_1.Widget();
var s = document.createElement('script');
s.type = options.mimetype;
s.textContent = options.source;
w.node.appendChild(s);
w.addClass(RENDERED_CLASS);
return w;
};
return JavascriptRenderer;
}());
exports.JavascriptRenderer = JavascriptRenderer;
/**
* A renderer for `<svg>` data.
*/
var SVGRenderer = (function () {
function SVGRenderer() {
/**
* The mimetypes this renderer accepts.
*/
this.mimetypes = ['image/svg+xml'];
}
/**
* Whether the input can safely sanitized for a given mimetype.
*/
SVGRenderer.prototype.sanitizable = function (mimetype) {
return this.mimetypes.indexOf(mimetype) !== -1;
};
/**
* Whether the input is safe without sanitization.
*/
SVGRenderer.prototype.isSafe = function (mimetype) {
return false;
};
/**
* Render the transformed mime bundle.
*/
SVGRenderer.prototype.render = function (options) {
var source = options.source;
if (options.sanitizer) {
source = options.sanitizer.sanitize(source);
}
var w = new phosphor_widget_1.Widget();
w.node.innerHTML = source;
var svgElement = w.node.getElementsByTagName('svg')[0];
if (!svgElement) {
throw new Error('SVGRender: Error: Failed to create <svg> element');
}
if (options.resolver) {
resolveUrls(w.node, options.resolver);
}
w.addClass(RENDERED_CLASS);
return w;
};
return SVGRenderer;
}());
exports.SVGRenderer = SVGRenderer;
/**
* A renderer for PDF data.
*/
var PDFRenderer = (function () {
function PDFRenderer() {
/**
* The mimetypes this renderer accepts.
*/
this.mimetypes = ['application/pdf'];
}
/**
* Whether the input can safely sanitized for a given mimetype.
*/
PDFRenderer.prototype.sanitizable = function (mimetype) {
return false;
};
/**
* Whether the input is safe without sanitization.
*/
PDFRenderer.prototype.isSafe = function (mimetype) {
return false;
};
/**
* Render the transformed mime bundle.
*/
PDFRenderer.prototype.render = function (options) {
var w = new phosphor_widget_1.Widget();
var a = document.createElement('a');
a.target = '_blank';
a.textContent = 'View PDF';
a.href = 'data:application/pdf;base64,' + options.source;
w.node.appendChild(a);
w.addClass(RENDERED_CLASS);
return w;
};
return PDFRenderer;
}());
exports.PDFRenderer = PDFRenderer;
/**
* A renderer for LateX data.
*/
var LatexRenderer = (function () {
function LatexRenderer() {
/**
* The mimetypes this renderer accepts.
*/
this.mimetypes = ['text/latex'];
}
/**
* Whether the input can safely sanitized for a given mimetype.
*/
LatexRenderer.prototype.sanitizable = function (mimetype) {
return false;
};
/**
* Whether the input is safe without sanitization.
*/
LatexRenderer.prototype.isSafe = function (mimetype) {
return this.mimetypes.indexOf(mimetype) !== -1;
};
/**
* Render the mime bundle.
*/
LatexRenderer.prototype.render = function (options) {
return new LatexWidget(options.source);
};
return LatexRenderer;
}());
exports.LatexRenderer = LatexRenderer;
/**
* A renderer for Jupyter Markdown data.
*/
var MarkdownRenderer = (function () {
function MarkdownRenderer() {
/**
* The mimetypes this renderer accepts.
*/
this.mimetypes = ['text/markdown'];
}
/**
* Whether the input can safely sanitized for a given mimetype.
*/
MarkdownRenderer.prototype.sanitizable = function (mimetype) {
return this.mimetypes.indexOf(mimetype) !== -1;
};
/**
* Whether the input is safe without sanitization.
*/
MarkdownRenderer.prototype.isSafe = function (mimetype) {
return false;
};
/**
* Render the mime bundle.
*/
MarkdownRenderer.prototype.render = function (options) {
return new MarkdownWidget(options);
};
return MarkdownRenderer;
}());
exports.MarkdownRenderer = MarkdownRenderer;
/**
* Resolve the relative urls in the image and anchor tags of a node tree.
*
* @param node - The head html element.
*
* @param resolver - A url resolver.
*/
function resolveUrls(node, resolver) {
var imgs = node.getElementsByTagName('img');
for (var i = 0; i < imgs.length; i++) {
var img = imgs[i];
var source = img.getAttribute('src');
if (source) {
img.src = resolver.resolveUrl(source);
}
}
var anchors = node.getElementsByTagName('a');
for (var i = 0; i < anchors.length; i++) {
var anchor = anchors[i];
var href = anchor.getAttribute('href');
if (href) {
anchor.href = resolver.resolveUrl(href);
}
}
}
exports.resolveUrls = resolveUrls;
/**
* Append trusted html to a node.
*/
function appendHtml(node, html) {
try {
var range = document.createRange();
node.appendChild(range.createContextualFragment(html));
}
catch (error) {
console.warn('Environment does not support Range ' +
'createContextualFragment, falling back on innerHTML');
node.innerHTML = html;
}
}