UNPKG

ng-prism

Version:

An Angular2 codeblock highlighting component using Prismjs.

257 lines (256 loc) 9.23 kB
"use strict"; var core_1 = require('@angular/core'); require('prismjs/components/prism-bash'); require('prismjs/components/prism-powershell'); require('prismjs/components/prism-javascript'); require('prismjs/plugins/line-numbers/prism-line-numbers'); require('prismjs/plugins/command-line/prism-command-line'); require('prismjs/plugins/normalize-whitespace/prism-normalize-whitespace'); /** * Represent template tags added by angular structural directives */ var TEMPLATE_REGEX = /<!--template\sbindings={[^\}]*}-->/g; /** * Code highlighting component * * Used internally by a codeblock to perform the actual highlighting. */ var CodeRendererComponent = (function () { function CodeRendererComponent(_renderer) { this._renderer = _renderer; } CodeRendererComponent.prototype.render = function () { this._replaceCode(); this._highlight(); }; /** * Clear the code. */ CodeRendererComponent.prototype.empty = function () { if (this._pre) { this._pre.nativeElement.innerHTML = ''; } }; /** * Place the new code element in the template */ CodeRendererComponent.prototype._replaceCode = function () { this._renderer.setElementProperty(this._pre.nativeElement, 'innerHTML', this._buildCodeElement()); }; /** * Perform the actual highlighting */ CodeRendererComponent.prototype._highlight = function () { // this._truncateLargeFiles(); Prism.highlightElement(this._pre.nativeElement.querySelector('code'), false, null); if (this.shell && this.outputLines) { this._fixPromptOutputPadding(); } }; Object.defineProperty(CodeRendererComponent.prototype, "_processedCode", { /** * Code prepared for highlighting and display */ get: function () { return this._isMarkup(this.language) ? this._processMarkup(this.code) : this.code; }, enumerable: true, configurable: true }); /** * Format markup for display. */ CodeRendererComponent.prototype._processMarkup = function (text) { return this._replaceTags(this._removeAngularMarkup(text)); }; /** * Change all opening < changed to &lt; to render markup correctly inside pre * tags */ CodeRendererComponent.prototype._replaceTags = function (text) { return text.replace(/(<)([!\/A-Za-z](.|[\n\r])*?>)/g, '&lt;$2'); }; /** * Remove both template tags and styling attributes added by the angular2 * parser and fix indentation within code elements created by structural * directives. */ CodeRendererComponent.prototype._removeAngularMarkup = function (html) { // remove styling attributes (_ngcontent etc.) html = html.replace(/\s_ng[^-]+-[^-]+-[^=]+="[^"]*"/g, ''); var lines = this._fixIndentation(html); // remove empty <!--template--> lines lines = lines.filter(function (line) { if (line.trim() === '') { return true; } var replaced = line.replace(TEMPLATE_REGEX, '') .trim(); return replaced !== ''; }); html = lines.join('\n'); // remove <!--template--> tags on lines with code return html.replace(TEMPLATE_REGEX, ''); }; /** * Is the language given a markup language? */ CodeRendererComponent.prototype._isMarkup = function (language) { return language === 'markup' || language === 'markdown'; }; /** * Create a <code> element with the proper classes and formatted code */ CodeRendererComponent.prototype._buildCodeElement = function () { return "<code class=\"" + this.codeClasses + "\">" + this._processedCode + "</code>"; }; Object.defineProperty(CodeRendererComponent.prototype, "languageClass", { /** * Styling classes */ get: function () { return 'language-' + this.language; }, enumerable: true, configurable: true }); Object.defineProperty(CodeRendererComponent.prototype, "lineNumbersClass", { get: function () { return this.lineNumbers ? 'line-numbers' : ''; }, enumerable: true, configurable: true }); Object.defineProperty(CodeRendererComponent.prototype, "shellClass", { get: function () { return this.shell ? 'command-line' : ''; }, enumerable: true, configurable: true }); Object.defineProperty(CodeRendererComponent.prototype, "codeClasses", { get: function () { return this.languageClass + ' ' + this.language; }, enumerable: true, configurable: true }); Object.defineProperty(CodeRendererComponent.prototype, "preClasses", { get: function () { return this.lineNumbersClass + ' ' + this.languageClass + ' ' + this.shellClass; }, enumerable: true, configurable: true }); Object.defineProperty(CodeRendererComponent.prototype, "_codeEl", { /* Code Styling **/ /** * The code element within <pre> */ get: function () { return this._pre.nativeElement.querySelector('code'); }, enumerable: true, configurable: true }); /** * Adds back padding on output shells because of floated left prompt */ CodeRendererComponent.prototype._fixPromptOutputPadding = function () { if (this._codeEl) { var clp = this._codeEl.querySelector('.command-line-prompt'); if (clp) { var promptWidth = this._codeEl.querySelector('.command-line-prompt').clientWidth; var prePadding = parseInt(this._getStyle(this._pre.nativeElement, 'padding-left') .replace('px', ''), 10); this._pre.nativeElement.style.paddingRight = (2 * prePadding + promptWidth / 2) + 'px'; } } }; /** * Get the actually applied style of an element */ CodeRendererComponent.prototype._getStyle = function (oElm, strCssRule) { var strValue = ''; if (document.defaultView && document.defaultView.getComputedStyle) { strValue = document.defaultView.getComputedStyle(oElm, '') .getPropertyValue(strCssRule); } else if (oElm.currentStyle) { strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1) { return p1.toUpperCase(); }); strValue = oElm.currentStyle[strCssRule]; } return strValue; }; // _truncateLargeFiles() { // if (this._codeEl.innerHTML.length > this.truncationSize) { // this._codeEl.innerHTML = this._codeEl.innerHTML.slice(0, // this.truncationSize) + "\n" + this.truncationMessage + "\n"; } } /** * Remove extra indentation in ngSwitches */ CodeRendererComponent.prototype._fixIndentation = function (html) { var indent = 0; var diff = 0; var removeLines = []; var lines = html.split('\n') .map(function (line, index) { if (line.trim() === '') { if (indent > 0) { removeLines.push(index); } indent = 0; return ''; } var a = line.replace(TEMPLATE_REGEX, '') .trim(); if (a === '') { indent = line.match(/^\s*/)[0].length; return line; } else if (indent > 0) { length = line.match(/^\s*/)[0].length; if (diff === 0) { diff = length - indent; } if (length >= indent) { return line.slice(diff); } else { indent = 0; } } return line; }); // remove empty lines added by ngSwitch removeLines.forEach(function (removalIndex) { lines.splice(removalIndex, 1); }); return lines; }; CodeRendererComponent.decorators = [ { type: core_1.Component, args: [{ selector: 'code-renderer', template: "\n<pre #preEl [class]=\"preClasses\" [attr.data-prompt]=\"prompt\" [attr.data-output]=\"outputLines\"></pre>\n " },] }, ]; /** @nocollapse */ CodeRendererComponent.ctorParameters = function () { return [ { type: core_1.Renderer, }, ]; }; CodeRendererComponent.propDecorators = { 'code': [{ type: core_1.Input },], 'language': [{ type: core_1.Input },], 'lineNumbers': [{ type: core_1.Input },], 'shell': [{ type: core_1.Input },], 'prompt': [{ type: core_1.Input },], 'outputLines': [{ type: core_1.Input },], '_pre': [{ type: core_1.ViewChild, args: ['preEl',] },], }; return CodeRendererComponent; }()); exports.CodeRendererComponent = CodeRendererComponent;