UNPKG

jupyterlab-emrys

Version:

A computational environment for Jupyter. Powered by Emrys

485 lines (484 loc) 14.3 kB
// Copyright (c) Jupyter Development Team. // Distributed under the terms of the Modified BSD License. "use strict"; 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; } }